diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50b3fd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +*.log +.DS_Store +.env +.env.local +.vscode/ +.idea/ \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..b6dc981 --- /dev/null +++ b/.npmignore @@ -0,0 +1,12 @@ +src/ +tsconfig.json +*.test.ts +.git/ +.github/ +examples/ +commands/ +CLAUDE.md +requirements/ +node_modules/ +.DS_Store +*.log \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f0dd254 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,112 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is the Claude Requirements Gathering System - a structured workflow for collecting and documenting software requirements through AI-guided interviews. The system provides both slash commands and an MCP server implementation, using a two-phase questioning approach (discovery + expert) with automated context gathering to generate comprehensive requirements documentation. + +## Repository Structure + +``` +claude-code-requirements-builder/ +├── src/ # MCP server source code +│ └── index.ts # Main MCP server implementation +├── dist/ # Built JavaScript files +├── commands/ # Claude slash command definitions +│ ├── requirements-start.md # Begin new requirement gathering +│ ├── requirements-status.md # Check progress (alias: current) +│ ├── requirements-current.md # View active requirement details +│ ├── requirements-end.md # Finalize requirement session +│ ├── requirements-list.md # List all requirements +│ └── requirements-remind.md # Remind AI of workflow rules +├── requirements/ # Generated requirement documents +│ ├── .current-requirement # Tracks active requirement +│ ├── index.md # Summary of all requirements +│ └── YYYY-MM-DD-HHMM-[name]/ # Individual requirement folders +├── examples/ # Sample requirement outputs +├── package.json # npm package configuration +└── tsconfig.json # TypeScript configuration +``` + +## Dual Implementation Architecture + +This system provides two ways to access the same functionality: + +### MCP Server (`src/index.ts`) +- **Node.js TypeScript implementation** using the official MCP SDK +- **6 registered tools** that mirror the slash commands: + - `requirements-start` - Begin new requirement gathering + - `requirements-status` - Check progress and session state + - `requirements-current` - View active requirement details + - `requirements-end` - Complete/incomplete/delete session + - `requirements-list` - Multi-requirement overview with status + - `requirements-remind` - Workflow rules and best practices reminder +- **File-based state management** using the same structure as slash commands +- **npx distribution** for easy installation and updates + +### Slash Commands (`commands/` directory) +Each command in `commands/` defines a specific workflow step: + +- **requirements-start.md**: 5-phase workflow (setup → discovery → context → expert → documentation) +- **requirements-status.md**: Progress tracking and session resumption +- **requirements-end.md**: Finalization with options (complete/incomplete/delete) +- **requirements-list.md**: Multi-requirement overview with status display + +## Key Workflow Patterns + +### Phase-Based Progression +1. **Setup**: Create timestamped folder, extract slug from request +2. **Discovery**: 5 yes/no questions about problem space +3. **Context**: Autonomous code analysis and file reading +4. **Expert**: 5 detailed yes/no questions with codebase knowledge +5. **Documentation**: Generate comprehensive requirements spec + +### Question Format Standards +- Only yes/no questions with intelligent defaults +- One question at a time (never batch) +- Write ALL questions to file BEFORE asking any +- Include "Default if unknown" reasoning for each question +- Use actual file paths and component names in expert phase + +### File Naming Conventions +- Requirement folders: `YYYY-MM-DD-HHMM-[feature-slug]` +- Sequential files: `00-initial-request.md` through `06-requirements-spec.md` +- Metadata tracking: `metadata.json` with phase/progress state + +### State Management +- `.current-requirement` file tracks active session +- `metadata.json` structure includes phase, progress counters, analyzed files +- Status transitions: discovery → context → detail → complete + +## Development Notes + +This repository provides dual implementation approaches: + +### MCP Server Development +- **TypeScript** with Node.js runtime +- **MCP SDK** for protocol compliance +- **Build system** with `npm run build` +- **npx distribution** for easy installation +- **State management** via JSON metadata files + +### Slash Commands +- **Documentation-based** system reading markdown files in `commands/` +- **No build system** required for slash commands +- **File-based workflow** definitions + +## Usage Patterns + +The system is designed for product managers and developers to gather requirements through: +- Simple yes/no responses (supports "idk" for defaults) +- Codebase-aware questioning after AI analysis +- Progressive refinement from high-level to implementation-specific +- Comprehensive documentation with file paths and implementation hints + +### MCP Server Usage +Users can install via `npx claude-code-requirements` and access all functionality through MCP tools in Claude Desktop or other MCP-compatible clients. + +### Slash Command Usage +For users preferring the original slash command interface, the `commands/` directory provides the same workflow through Claude Code's built-in command system. + +When working with this repository, maintain consistency between both implementations and ensure the workflow preserves its structured, phase-based approach while keeping questions simple and defaults intelligent. \ No newline at end of file diff --git a/README.md b/README.md index d6fc1d0..1458690 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Claude Requirements Gathering System -An intelligent requirements gathering system for Claude Code that progressively builds context through automated discovery, asks simple yes/no questions, and generates comprehensive requirements documentation. +An intelligent requirements gathering system that combines slash commands and MCP server for Claude Code. It progressively builds context through automated discovery, asks simple yes/no questions, and generates comprehensive requirements documentation. ## 🎯 Overview @@ -10,9 +10,43 @@ This system transforms the requirements gathering process by: - **Two-Phase Questioning**: 5 high-level questions for context, then 5 expert questions after code analysis - **Automated Documentation**: Generates comprehensive specs with specific file paths and patterns - **Product Manager Friendly**: No code knowledge required to answer questions +- **MCP Server Support**: Available as both slash commands and MCP tools +- **Complete Development Loop**: New `/synthesize` command transforms requirements into implementation ## 🚀 Quick Start +### Option 1: Using MCP Server (Recommended) + +**Install via npm:** +```bash +# Test it works +npx claude-code-requirements + +# Add to Claude Desktop config +``` + +Add to your `claude_desktop_config.json`: +```json +{ + "mcpServers": { + "claude-code-requirements": { + "command": "npx", + "args": ["claude-code-requirements"] + } + } +} +``` + +Then use the MCP tools: +- `requirements-start` - Begin gathering requirements +- `requirements-status` - Check progress +- `requirements-current` - View active requirement +- `requirements-end` - Complete/cancel session +- `requirements-list` - List all requirements +- `requirements-remind` - Get workflow reminder + +### Option 2: Using Slash Commands + ```bash # Start gathering requirements for a new feature /requirements-start add user profile picture upload @@ -29,6 +63,9 @@ This system transforms the requirements gathering process by: # End current requirement gathering /requirements-end +# Generate implementation plan from completed requirements +/synthesize + # Quick reminder if AI strays off course /remind ``` @@ -43,7 +80,8 @@ claude-requirements/ │ ├── requirements-current.md # View active requirement │ ├── requirements-end.md # Finalize requirement │ ├── requirements-list.md # List all requirements -│ └── requirements-remind.md # Remind AI of rules +│ ├── requirements-remind.md # Remind AI of rules +│ └── synthesize.md # Generate implementation from requirements │ ├── requirements/ # Requirement documentation storage │ ├── .current-requirement # Tracks active requirement @@ -165,6 +203,27 @@ Reminds AI to follow requirements gathering rules. - Starts implementing code - Asks multiple questions at once +### `/synthesize` +Transforms completed requirements into actionable implementation plans. + +**Features:** +- Finds most recent completed requirement automatically +- Generates phased implementation plan +- Creates tracked todo list with specific tasks +- Maps tasks to requirement IDs (FR/TR) +- Begins actual implementation with progress tracking + +**Example:** +``` +/synthesize +``` + +**Output:** +- Implementation plan document +- Todo list with task IDs +- Automatic loading into Claude's task tracker +- Begins implementation immediately + ## 🎯 Features ### Smart Defaults @@ -205,9 +264,35 @@ Every question includes an intelligent default based on: ## 🔧 Installation +### MCP Server Installation (Recommended) + +Install the MCP server via npm: + +```bash +# Test it works +npx claude-code-requirements + +# Or install globally +npm install -g claude-code-requirements +``` + +Add to your Claude Desktop configuration: +```json +{ + "mcpServers": { + "claude-code-requirements": { + "command": "npx", + "args": ["claude-code-requirements"] + } + } +} +``` + +### Slash Commands Installation + 1. Clone this repository: ```bash -git clone https://github.com/rizethereum/claude-code-requirements-builder.git +git clone https://github.com/ulasbilgen/claude-code-requirements-builder.git ``` 2. Copy the commands to your project: diff --git a/commands/synthesize.md b/commands/synthesize.md new file mode 100644 index 0000000..27f2fc9 --- /dev/null +++ b/commands/synthesize.md @@ -0,0 +1,146 @@ +# Synthesize Requirements into Implementation + +Analyzes completed requirements and generates a detailed implementation plan with tracked todo steps + +aliases: synth, implement + +## Instructions + +When the user runs the `synthesize` command: + +1. **Enter Planning Mode** + - Activate Claude's planning mode to ensure thoughtful analysis + - Prepare for comprehensive requirements review and implementation planning + +2. **Find Most Recent Completed Requirements** + - Navigate to `requirements/` directory in the current working directory + - Look for subdirectories with timestamp format (YYYY-MM-DD_HH-MM-SS_*) + - Find the most recent directory containing a `metadata.json` with `"status": "complete"` + - Extract the requirement name from the directory (part after timestamp) + +3. **Load and Analyze Requirements** + - Read `06-requirements-spec.md` from the identified directory + - Parse the following sections: + - Problem Statement + - Solution Overview + - Functional Requirements (FR*) + - Technical Requirements (TR*) + - Implementation Hints + - Acceptance Criteria + - Read `03-context-findings.md` for technical context + - Read `metadata.json` for related features and context files + +4. **Generate Implementation Plan** + Create a detailed implementation plan with the following structure: + ```markdown + # Implementation Plan: [Requirement Name] + Generated: [Current Timestamp] + Based on: [Original Requirements Timestamp] + + ## Overview + [Brief summary of what will be implemented] + + ## Prerequisites + - [ ] List any setup requirements + - [ ] Dependencies to install + - [ ] Files to create/modify + + ## Implementation Phases + + ### Phase 1: [Foundation/Setup] + **Objective**: [What this phase accomplishes] + **Requirements Addressed**: [FR/TR numbers] + + Steps: + 1. [Specific action with file:line references] + 2. [Next action] + ... + + ### Phase 2: [Core Implementation] + [Continue pattern for each logical phase] + + ## Testing Strategy + - Unit tests for [components] + - Integration tests for [features] + - Manual testing checklist + + ## Validation Against Acceptance Criteria + [Map each acceptance criterion to implementation steps] + ``` + +5. **Generate Todo List** + Create a structured todo list from the implementation plan: + ```markdown + # Implementation Todo: [Requirement Name] + Generated: [Current Timestamp] + Total Steps: [Number] + + ## Setup Tasks + - [ ] SETUP-1: [Task description] | File: [path] | Priority: High + - [ ] SETUP-2: [Task description] | File: [path] | Priority: High + + ## Phase 1 Tasks + - [ ] P1-1: [Task description] | File: [path] | Priority: High + - [ ] P1-2: [Task description] | File: [path] | Priority: Medium + + ## Phase 2 Tasks + [Continue pattern] + + ## Testing Tasks + - [ ] TEST-1: [Test description] | Type: [unit/integration/manual] + + ## Validation Tasks + - [ ] VAL-1: Verify [acceptance criterion] + ``` + +6. **Save Plan and Todo List** + - Create subdirectory: `[requirements-dir]/implementation/` + - Save files with timestamps: + - `implementation-plan_[timestamp].md` + - `implementation-todo_[timestamp].md` + - Create a `current` symlink to latest files for easy access + +7. **Begin Implementation** + - Exit planning mode with the generated plan + - Load the todo list into Claude's TodoWrite tool + - Start with SETUP tasks, marking each as `in_progress` then `completed` + - Follow any project-specific guidance from CLAUDE.md if present + - For each task: + 1. Mark as `in_progress` in TodoWrite + 2. Implement the specific change + 3. Run any relevant tests/lints + 4. Mark as `completed` in TodoWrite + 5. Update the saved todo file with completion status + +8. **Progress Tracking** + - Periodically save progress to `implementation-todo_[timestamp].md` + - Add completion timestamps to finished items + - If blocked on any task, add a `BLOCKED:` prefix and explanation + - Create `implementation-notes_[timestamp].md` for any discoveries or changes + +## Error Handling + +- If no completed requirements found: "No completed requirements found in requirements/" +- If requirements incomplete: "Found requirement [name] but status is [status], not 'complete'" +- If missing required files: List which files are missing from the requirement + +## Example Usage + +``` +synthesize +``` + +This will: +1. Find the most recent completed requirement in `requirements/` +2. Generate a detailed implementation plan +3. Create a todo list with specific tasks +4. Save both in the requirements directory +5. Begin implementing while tracking progress + +## Notes + +- The command respects any coding standards in the project's CLAUDE.md file +- Each task in the todo list maps to specific requirement items (FR/TR) +- Progress is saved incrementally to prevent loss of work +- The implementation follows the phases defined in the plan +- Testing and validation are integrated into the workflow \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..dc1ec89 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,3 @@ +#!/usr/bin/env node +export {}; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map new file mode 100644 index 0000000..535b86d --- /dev/null +++ b/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100755 index 0000000..92dbe25 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,799 @@ +#!/usr/bin/env node +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { z } from "zod"; +import { promises as fs } from "fs"; +import { join, dirname } from "path"; +import { fileURLToPath } from "url"; +const __dirname = dirname(fileURLToPath(import.meta.url)); +const DEFAULT_SETTINGS = { + discoveryQuestions: 5, + expertQuestions: 5 +}; +// Load settings from file or use defaults +async function loadSettings() { + const requirementsDir = join(process.cwd(), 'requirements'); + const settingsPath = join(requirementsDir, '.mcp-settings.json'); + try { + // Ensure requirements directory exists before reading + await ensureDir(requirementsDir); + const content = await fs.readFile(settingsPath, 'utf-8'); + const parsed = JSON.parse(content); + return { ...DEFAULT_SETTINGS, ...parsed }; + } + catch { + // If file doesn't exist or can't be read, return defaults + return DEFAULT_SETTINGS; + } +} +// Save settings to file +async function saveSettings(settings) { + const requirementsDir = join(process.cwd(), 'requirements'); + await ensureDir(requirementsDir); + const settingsPath = join(requirementsDir, '.mcp-settings.json'); + await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2)); +} +// Create the MCP server +const server = new McpServer({ + name: "claude-code-requirements", + version: "1.2.1" +}); +// Helper functions for file operations +async function ensureDir(dirPath) { + try { + await fs.mkdir(dirPath, { recursive: true }); + } + catch (error) { + // Directory might already exist + } +} +async function fileExists(filePath) { + try { + await fs.access(filePath); + return true; + } + catch { + return false; + } +} +async function readFileIfExists(filePath) { + try { + return await fs.readFile(filePath, 'utf-8'); + } + catch { + return null; + } +} +async function getCurrentRequirement() { + const currentFile = join(process.cwd(), 'requirements', '.current-requirement'); + return await readFileIfExists(currentFile); +} +async function setCurrentRequirement(folderName) { + const requirementsDir = join(process.cwd(), 'requirements'); + await ensureDir(requirementsDir); + const currentFile = join(requirementsDir, '.current-requirement'); + await fs.writeFile(currentFile, folderName); +} +async function clearCurrentRequirement() { + const currentFile = join(process.cwd(), 'requirements', '.current-requirement'); + try { + await fs.unlink(currentFile); + } + catch { + // File might not exist + } +} +function createTimestampFolder(name) { + const now = new Date(); + const timestamp = now.toISOString() + .slice(0, 16) + .replace('T', '-') + .replace(':', ''); + const slug = name + .toLowerCase() + .replace(/[^a-z0-9\s-]/g, '') + .replace(/\s+/g, '-') + .slice(0, 30); + return `${timestamp}-${slug}`; +} +// Tool: requirements-start +server.registerTool("requirements-start", { + title: "Start Requirements Gathering", + description: "Begin gathering requirements for a new feature or project", + inputSchema: { + request: z.string().describe("The feature or project request to gather requirements for") + } +}, async ({ request }) => { + try { + // Check if there's already an active requirement + const currentRequirement = await getCurrentRequirement(); + if (currentRequirement) { + return { + content: [{ + type: "text", + text: `❌ There is already an active requirement session: ${currentRequirement}\n\nPlease complete it first with 'requirements-end' or check its status with 'requirements-status'.` + }] + }; + } + // Create timestamped folder + const folderName = createTimestampFolder(request); + const requirementPath = join(process.cwd(), 'requirements', folderName); + await ensureDir(requirementPath); + // Load settings to determine question counts + const settings = await loadSettings(); + // Create initial files + const initialRequestContent = `# Initial Request\n\n**Timestamp:** ${new Date().toISOString()}\n\n**Request:** ${request}\n\n---\n\nThis is the starting point for requirements gathering session: ${folderName}\n`; + const metadata = { + id: folderName.split('-').slice(-1)[0], + started: new Date().toISOString(), + lastUpdated: new Date().toISOString(), + status: "active", + phase: "discovery", + progress: { + discovery: { answered: 0, total: settings.discoveryQuestions }, + detail: { answered: 0, total: settings.expertQuestions } + }, + contextFiles: [], + relatedFeatures: [], + settings: settings + }; + await fs.writeFile(join(requirementPath, '00-initial-request.md'), initialRequestContent); + await fs.writeFile(join(requirementPath, 'metadata.json'), JSON.stringify(metadata, null, 2)); + // Set as current requirement + await setCurrentRequirement(folderName); + // Generate and save discovery questions + const discoveryQuestions = generateDiscoveryQuestions(settings.discoveryQuestions); + const questionsContent = `# Discovery Questions\n\n**Generated:** ${new Date().toISOString()}\n**Total Questions:** ${settings.discoveryQuestions}\n\n` + + discoveryQuestions.map((q, index) => `## Q${index + 1}: ${q.question}\n**Default if unknown:** ${q.defaultValue ? 'Yes' : 'No'} (${q.reason})\n`).join('\n'); + await fs.writeFile(join(requirementPath, '01-discovery-questions.md'), questionsContent); + return { + content: [{ + type: "text", + text: `✅ Requirements gathering started for: "${request}"\n\n📁 Created folder: requirements/${folderName}\n📝 Session is now active\n\n**Settings:**\n- Discovery Questions: ${settings.discoveryQuestions}\n- Expert Questions: ${settings.expertQuestions}\n\n**Next Steps:**\n1. Use 'requirements-status' to continue with discovery questions\n2. The system will guide you through the 5-phase workflow:\n - Phase 1: Setup & Codebase Analysis ✅\n - Phase 2: Context Discovery Questions (${settings.discoveryQuestions} questions)\n - Phase 3: Targeted Context Gathering\n - Phase 4: Expert Requirements Questions (${settings.expertQuestions} questions)\n - Phase 5: Requirements Documentation\n\n**Current Phase:** Discovery - Ready to ask ${settings.discoveryQuestions} yes/no questions` + }] + }; + } + catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error starting requirements gathering: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } +}); +// Tool: requirements-status +server.registerTool("requirements-status", { + title: "Check Requirements Status and Continue", + description: "Check the status and progress of the current requirements gathering session and continue the workflow", + inputSchema: {} +}, async () => { + try { + const currentRequirement = await getCurrentRequirement(); + if (!currentRequirement) { + return { + content: [{ + type: "text", + text: `📋 **No Active Requirements Session**\n\nTo start a new requirements gathering session:\n- Use 'requirements-start' with your feature request\n\nTo view previous sessions:\n- Use 'requirements-list' to see all requirements` + }] + }; + } + const requirementPath = join(process.cwd(), 'requirements', currentRequirement); + const metadataPath = join(requirementPath, 'metadata.json'); + if (!await fileExists(metadataPath)) { + return { + content: [{ + type: "text", + text: `❌ Metadata file not found for active session: ${currentRequirement}` + }], + isError: true + }; + } + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + // If we're in discovery phase and have unanswered questions, continue asking + if (metadata.phase === "discovery" && metadata.progress.discovery.answered < metadata.progress.discovery.total) { + const currentQuestionIndex = metadata.progress.discovery.answered; + const settings = metadata.settings || await loadSettings(); + const discoveryQuestions = generateDiscoveryQuestions(settings.discoveryQuestions); + const currentQuestion = discoveryQuestions[currentQuestionIndex]; + // Ask the current question using elicitation + const answer = await askQuestion(server, `Discovery Question ${currentQuestionIndex + 1}/${metadata.progress.discovery.total}: ${currentQuestion.question}`, currentQuestion.defaultValue, currentQuestion.reason); + // Update progress + metadata.progress.discovery.answered++; + metadata.lastUpdated = new Date().toISOString(); + // Save the answer to the answers file + const answersPath = join(requirementPath, '02-discovery-answers.md'); + let answersContent = ''; + if (await fileExists(answersPath)) { + answersContent = await fs.readFile(answersPath, 'utf-8'); + } + else { + answersContent = `# Discovery Answers\n\n**Started:** ${new Date().toISOString()}\n\n`; + } + answersContent += `## Q${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n**Reasoning:** ${currentQuestion.reason}\n\n`; + await fs.writeFile(answersPath, answersContent); + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + // Check if discovery phase is complete + if (metadata.progress.discovery.answered >= metadata.progress.discovery.total) { + metadata.phase = "context"; + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + return { + content: [{ + type: "text", + text: `✅ **Discovery Phase Complete!**\n\nAnswered: ${answer ? 'Yes' : 'No'} to "${currentQuestion.question}"\n\n🎉 All ${metadata.progress.discovery.total} discovery questions completed!\n\n**Next Phase:** Context Gathering\n- The system will now analyze the codebase based on your answers\n- Use 'requirements-status' again to continue to expert questions` + }] + }; + } + else { + return { + content: [{ + type: "text", + text: `✅ **Question Answered**\n\nQ${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n\n**Progress:** ${metadata.progress.discovery.answered}/${metadata.progress.discovery.total} discovery questions completed\n\nUse 'requirements-status' again to continue with the next question.` + }] + }; + } + } + // If in context phase, move to detail questions + if (metadata.phase === "context") { + metadata.phase = "detail"; + metadata.lastUpdated = new Date().toISOString(); + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + return { + content: [{ + type: "text", + text: `📋 **Context Phase Complete**\n\nMoving to Expert Questions phase...\n\n**Next:** ${metadata.progress.detail.total} expert questions about system behavior\n\nUse 'requirements-status' again to start expert questions.` + }] + }; + } + // If we're in detail phase and have unanswered questions, continue asking + if (metadata.phase === "detail" && metadata.progress.detail.answered < metadata.progress.detail.total) { + const currentQuestionIndex = metadata.progress.detail.answered; + // For now, use basic expert questions - in a full implementation, these would be generated based on context analysis + const expertQuestions = [ + { + question: "Should this feature be accessible to all user roles?", + defaultValue: false, + reason: "role-based access is more common for new features" + }, + { + question: "Will this feature require database schema changes?", + defaultValue: true, + reason: "most new features need new data structures" + }, + { + question: "Should this feature have comprehensive error handling and validation?", + defaultValue: true, + reason: "robust error handling is a best practice" + }, + { + question: "Will this feature need to be backwards compatible with existing APIs?", + defaultValue: true, + reason: "maintaining API compatibility is usually required" + }, + { + question: "Should this feature include comprehensive logging and monitoring?", + defaultValue: true, + reason: "observability is critical for production features" + } + ].slice(0, metadata.progress.detail.total); + const currentQuestion = expertQuestions[currentQuestionIndex]; + // Ask the current expert question using elicitation + const answer = await askQuestion(server, `Expert Question ${currentQuestionIndex + 1}/${metadata.progress.detail.total}: ${currentQuestion.question}`, currentQuestion.defaultValue, currentQuestion.reason); + // Update progress + metadata.progress.detail.answered++; + metadata.lastUpdated = new Date().toISOString(); + // Save the answer to the detail answers file + const detailAnswersPath = join(requirementPath, '05-detail-answers.md'); + let detailAnswersContent = ''; + if (await fileExists(detailAnswersPath)) { + detailAnswersContent = await fs.readFile(detailAnswersPath, 'utf-8'); + } + else { + detailAnswersContent = `# Expert Question Answers\n\n**Started:** ${new Date().toISOString()}\n\n`; + } + detailAnswersContent += `## Q${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n**Reasoning:** ${currentQuestion.reason}\n\n`; + await fs.writeFile(detailAnswersPath, detailAnswersContent); + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + // Check if detail phase is complete + if (metadata.progress.detail.answered >= metadata.progress.detail.total) { + metadata.phase = "complete"; + metadata.status = "completed"; + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + return { + content: [{ + type: "text", + text: `✅ **Expert Questions Complete!**\n\nAnswered: ${answer ? 'Yes' : 'No'} to "${currentQuestion.question}"\n\n🎉 All ${metadata.progress.detail.total} expert questions completed!\n\n**Status:** Requirements gathering complete\n**Next:** Use 'requirements-end' to finalize the session\n\nAll answers have been saved and the requirements specification can now be generated.` + }] + }; + } + else { + return { + content: [{ + type: "text", + text: `✅ **Expert Question Answered**\n\nQ${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n\n**Progress:** ${metadata.progress.detail.answered}/${metadata.progress.detail.total} expert questions completed\n\nUse 'requirements-status' again to continue with the next question.` + }] + }; + } + } + // Show status for completed or other phases + const phaseDescriptions = { + discovery: "Context Discovery Questions (understanding problem space)", + context: "Targeted Context Gathering (autonomous codebase analysis)", + detail: "Expert Requirements Questions (detailed system behavior)", + complete: "Requirements Documentation (comprehensive spec generation)" + }; + let statusText = `📋 **Requirements Session Status**\n\n`; + statusText += `**Session:** ${currentRequirement}\n`; + statusText += `**Started:** ${new Date(metadata.started).toLocaleString()}\n`; + statusText += `**Last Updated:** ${new Date(metadata.lastUpdated).toLocaleString()}\n`; + statusText += `**Status:** ${metadata.status}\n`; + statusText += `**Current Phase:** ${metadata.phase} - ${phaseDescriptions[metadata.phase] || 'Unknown'}\n\n`; + statusText += `**Progress:**\n`; + if (metadata.progress.discovery) { + statusText += `- Discovery Questions: ${metadata.progress.discovery.answered}/${metadata.progress.discovery.total} answered\n`; + } + if (metadata.progress.detail) { + statusText += `- Expert Questions: ${metadata.progress.detail.answered}/${metadata.progress.detail.total} answered\n`; + } + if (metadata.contextFiles && metadata.contextFiles.length > 0) { + statusText += `\n**Analyzed Files:** ${metadata.contextFiles.length} files\n`; + } + statusText += `\n**Available Actions:**\n`; + statusText += `- 'requirements-current' - View detailed session info\n`; + statusText += `- 'requirements-end' - Complete or cancel session\n`; + return { + content: [{ + type: "text", + text: statusText + }] + }; + } + catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error checking requirements status: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } +}); +// Tool: requirements-current +server.registerTool("requirements-current", { + title: "View Current Requirements Details", + description: "View detailed information about the current requirements gathering session", + inputSchema: {} +}, async () => { + try { + const currentRequirement = await getCurrentRequirement(); + if (!currentRequirement) { + return { + content: [{ + type: "text", + text: `📋 No active requirements session. Use 'requirements-start' to begin.` + }] + }; + } + const requirementPath = join(process.cwd(), 'requirements', currentRequirement); + // Read all relevant files + const files = await fs.readdir(requirementPath); + const mdFiles = files.filter(f => f.endsWith('.md')).sort(); + let content = `📋 **Current Requirements Session: ${currentRequirement}**\n\n`; + // Show each file content + for (const file of mdFiles) { + const filePath = join(requirementPath, file); + const fileContent = await fs.readFile(filePath, 'utf-8'); + content += `## ${file}\n\n`; + content += `${fileContent}\n\n---\n\n`; + } + // Show metadata + const metadataPath = join(requirementPath, 'metadata.json'); + if (await fileExists(metadataPath)) { + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + content += `## Metadata\n\n`; + content += `\`\`\`json\n${JSON.stringify(metadata, null, 2)}\n\`\`\`\n`; + } + return { + content: [{ + type: "text", + text: content + }] + }; + } + catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error viewing current requirements: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } +}); +// Tool: requirements-end +server.registerTool("requirements-end", { + title: "End Requirements Session", + description: "Complete, mark as incomplete, or delete the current requirements gathering session", + inputSchema: { + action: z.enum(["complete", "incomplete", "delete"]).describe("Action to take: complete (mark as finished), incomplete (save but mark unfinished), delete (remove entirely)") + } +}, async ({ action }) => { + try { + const currentRequirement = await getCurrentRequirement(); + if (!currentRequirement) { + return { + content: [{ + type: "text", + text: `❌ No active requirements session to end.` + }] + }; + } + const requirementPath = join(process.cwd(), 'requirements', currentRequirement); + const metadataPath = join(requirementPath, 'metadata.json'); + if (action === "delete") { + // Delete the entire requirement folder + await fs.rm(requirementPath, { recursive: true, force: true }); + await clearCurrentRequirement(); + return { + content: [{ + type: "text", + text: `🗑️ **Requirements session deleted**\n\nDeleted: ${currentRequirement}\nNo active session remaining.` + }] + }; + } + // Update metadata for complete/incomplete + if (await fileExists(metadataPath)) { + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + metadata.status = action === "complete" ? "completed" : "incomplete"; + metadata.lastUpdated = new Date().toISOString(); + metadata.endedAt = new Date().toISOString(); + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + } + // Update requirements index + const indexPath = join(process.cwd(), 'requirements', 'index.md'); + const indexExists = await fileExists(indexPath); + let indexContent = indexExists ? await fs.readFile(indexPath, 'utf-8') : + `# Requirements Index\n\nThis file tracks all requirements gathering sessions.\n\n`; + const statusEmoji = action === "complete" ? "✅" : "⚠️"; + const statusText = action === "complete" ? "Completed" : "Incomplete"; + const newEntry = `- ${statusEmoji} **${currentRequirement}** - ${statusText} (${new Date().toLocaleDateString()})\n`; + if (!indexContent.includes(currentRequirement)) { + indexContent += newEntry; + await fs.writeFile(indexPath, indexContent); + } + await clearCurrentRequirement(); + return { + content: [{ + type: "text", + text: `${statusEmoji} **Requirements session ${action === "complete" ? "completed" : "marked incomplete"}**\n\nSession: ${currentRequirement}\nStatus: ${statusText}\nNo active session remaining.\n\nUse 'requirements-list' to view all sessions.` + }] + }; + } + catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error ending requirements session: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } +}); +// Tool: requirements-list +server.registerTool("requirements-list", { + title: "List All Requirements", + description: "List all requirements gathering sessions (active and completed)", + inputSchema: {} +}, async () => { + try { + const requirementsDir = join(process.cwd(), 'requirements'); + if (!await fileExists(requirementsDir)) { + return { + content: [{ + type: "text", + text: `📋 **No Requirements Sessions Found**\n\nThe requirements/ directory doesn't exist yet.\nUse 'requirements-start' to create your first session.` + }] + }; + } + const entries = await fs.readdir(requirementsDir, { withFileTypes: true }); + const folders = entries.filter(entry => entry.isDirectory()).map(entry => entry.name); + if (folders.length === 0) { + return { + content: [{ + type: "text", + text: `📋 **No Requirements Sessions Found**\n\nUse 'requirements-start' to create your first session.` + }] + }; + } + const currentRequirement = await getCurrentRequirement(); + let content = `📋 **All Requirements Sessions**\n\n`; + // Sort folders by timestamp (newest first) + const sortedFolders = folders.sort().reverse(); + for (const folder of sortedFolders) { + const folderPath = join(requirementsDir, folder); + const metadataPath = join(folderPath, 'metadata.json'); + let status = "Unknown"; + let phase = "Unknown"; + let started = "Unknown"; + if (await fileExists(metadataPath)) { + try { + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + status = metadata.status || "Unknown"; + phase = metadata.phase || "Unknown"; + started = metadata.started ? new Date(metadata.started).toLocaleDateString() : "Unknown"; + } + catch { + // Ignore metadata read errors + } + } + const isActive = folder === currentRequirement; + const activeIndicator = isActive ? " 🟢 **ACTIVE**" : ""; + const statusEmoji = status === "completed" ? "✅" : status === "incomplete" ? "⚠️" : status === "active" ? "🟡" : "❓"; + content += `${statusEmoji} **${folder}**${activeIndicator}\n`; + content += ` Status: ${status} | Phase: ${phase} | Started: ${started}\n\n`; + } + content += `**Actions:**\n`; + content += `- 'requirements-start' - Start new session\n`; + if (currentRequirement) { + content += `- 'requirements-status' - Check active session\n`; + content += `- 'requirements-current' - View active session details\n`; + } + return { + content: [{ + type: "text", + text: content + }] + }; + } + catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error listing requirements: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } +}); +// Tool: requirements-remind +server.registerTool("requirements-remind", { + title: "Workflow Reminder", + description: "Get a reminder of the requirements gathering workflow rules and best practices", + inputSchema: {} +}, async () => { + const reminderContent = `📚 **Requirements Gathering Workflow Reminder** + +## 5-Phase Workflow: + +### Phase 1: Initial Setup & Codebase Analysis +- Create timestamp-based folder +- Extract slug from request +- Create initial files (00-initial-request.md, metadata.json) +- Set as current requirement +- Analyze overall codebase structure + +### Phase 2: Context Discovery Questions +- Generate 5 most important yes/no questions about problem space +- Questions about user interactions, workflows, similar features +- Questions about data/content, integrations, performance +- Write ALL questions to 01-discovery-questions.md with smart defaults +- Ask questions ONE AT A TIME +- Record answers in 02-discovery-answers.md + +### Phase 3: Targeted Context Gathering (Autonomous) +- Search for specific files based on discovery answers +- Deep dive into similar features and patterns +- Analyze implementation details +- Document findings in 03-context-findings.md with: + - Specific files that need modification + - Exact patterns to follow + - Technical constraints and considerations + +### Phase 4: Expert Requirements Questions +- Ask 5 detailed yes/no questions like a senior developer +- Questions about expected system behavior using codebase knowledge +- Include smart defaults based on codebase patterns +- Write to 04-detail-questions.md, ask one at a time +- Record answers in 05-detail-answers.md + +### Phase 5: Requirements Documentation +- Generate comprehensive spec in 06-requirements-spec.md: + - Problem statement and solution overview + - Functional requirements based on all answers + - Technical requirements with specific file paths + - Implementation hints and patterns + - Acceptance criteria + - Assumptions for unanswered questions + +## Key Rules: +- **ONLY yes/no questions** with smart defaults +- **ONE question at a time** (never batch) +- **Write ALL questions to file BEFORE asking any** +- Use actual file paths and component names in detail phase +- Document WHY each default makes sense +- Stay focused on requirements (no implementation) + +## Current Status: +Use 'requirements-status' to see your current phase and progress.`; + return { + content: [{ + type: "text", + text: reminderContent + }] + }; +}); +// Tool: requirements-settings +server.registerTool("requirements-settings", { + title: "Configure Requirements Settings", + description: "Interactively configure the number of discovery and expert questions", + inputSchema: {} +}, async () => { + try { + const currentSettings = await loadSettings(); + // Show current settings first + let resultMessage = `📋 **Current Settings**\n\n**Discovery Questions:** ${currentSettings.discoveryQuestions}\n**Expert Questions:** ${currentSettings.expertQuestions}\n\n`; + // Ask for discovery questions count + const discoveryResult = await server.server.elicitInput({ + message: `Discovery Questions (current: ${currentSettings.discoveryQuestions})`, + requestedSchema: { + type: "object", + properties: { + count: { + type: "number", + title: "Number of Discovery Questions", + description: `Current: ${currentSettings.discoveryQuestions}. Press Enter to keep current value, or enter a number between 1-20`, + default: currentSettings.discoveryQuestions, + minimum: 1, + maximum: 20 + } + }, + required: ["count"] + } + }); + const newDiscoveryCount = (discoveryResult.action === "accept" && discoveryResult.content?.count) + ? discoveryResult.content.count + : currentSettings.discoveryQuestions; + // Ask for expert questions count + const expertResult = await server.server.elicitInput({ + message: `Expert Questions (current: ${currentSettings.expertQuestions})`, + requestedSchema: { + type: "object", + properties: { + count: { + type: "number", + title: "Number of Expert Questions", + description: `Current: ${currentSettings.expertQuestions}. Press Enter to keep current value, or enter a number between 1-20`, + default: currentSettings.expertQuestions, + minimum: 1, + maximum: 20 + } + }, + required: ["count"] + } + }); + const newExpertCount = (expertResult.action === "accept" && expertResult.content?.count) + ? expertResult.content.count + : currentSettings.expertQuestions; + // Check if anything changed + if (newDiscoveryCount === currentSettings.discoveryQuestions && newExpertCount === currentSettings.expertQuestions) { + return { + content: [{ + type: "text", + text: `📋 **Settings Unchanged**\n\n**Discovery Questions:** ${currentSettings.discoveryQuestions}\n**Expert Questions:** ${currentSettings.expertQuestions}\n\nNo changes were made to the settings.` + }] + }; + } + // Save new settings + const newSettings = { + discoveryQuestions: newDiscoveryCount, + expertQuestions: newExpertCount + }; + await saveSettings(newSettings); + return { + content: [{ + type: "text", + text: `✅ **Settings Updated**\n\n**Discovery Questions:** ${newSettings.discoveryQuestions} ${newSettings.discoveryQuestions !== currentSettings.discoveryQuestions ? '(changed)' : ''}\n**Expert Questions:** ${newSettings.expertQuestions} ${newSettings.expertQuestions !== currentSettings.expertQuestions ? '(changed)' : ''}\n\nSettings saved to requirements/.mcp-settings.json` + }] + }; + } + catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error managing settings: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } +}); +// Helper function to ask a single question using elicitation +async function askQuestion(mcpServer, questionText, defaultValue, defaultReason) { + const result = await mcpServer.server.elicitInput({ + message: questionText, + requestedSchema: { + type: "object", + properties: { + answer: { + type: "boolean", + title: "Answer", + description: `Default: ${defaultValue ? 'Yes' : 'No'} (${defaultReason})`, + default: defaultValue + } + }, + required: ["answer"] + } + }); + if (result.action === "accept" && result.content?.answer !== undefined) { + return result.content.answer; + } + // If user cancels or rejects, use default + return defaultValue; +} +// Helper function to generate discovery questions +function generateDiscoveryQuestions(count) { + const allQuestions = [ + { + question: "Will users interact with this feature through a visual interface?", + defaultValue: true, + reason: "most features have some UI component" + }, + { + question: "Does this feature need to work on mobile devices?", + defaultValue: true, + reason: "mobile-first is standard practice" + }, + { + question: "Will this feature handle sensitive or private user data?", + defaultValue: true, + reason: "better to be secure by default" + }, + { + question: "Do users currently have a workaround for this problem?", + defaultValue: false, + reason: "assuming this solves a new need" + }, + { + question: "Will this feature need to work offline?", + defaultValue: false, + reason: "most features require connectivity" + }, + { + question: "Will this feature require real-time updates or notifications?", + defaultValue: false, + reason: "real-time features add complexity" + }, + { + question: "Does this feature need to integrate with external APIs or services?", + defaultValue: false, + reason: "internal features are more common" + }, + { + question: "Will this feature need to scale to handle many concurrent users?", + defaultValue: true, + reason: "better to plan for scale upfront" + }, + { + question: "Does this feature require user authentication or authorization?", + defaultValue: true, + reason: "most features need some level of access control" + }, + { + question: "Will this feature need to maintain audit logs or activity history?", + defaultValue: false, + reason: "audit logs are typically for specific use cases" + } + ]; + return allQuestions.slice(0, count); +} +// Connect the server +async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); +} +main().catch(console.error); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 0000000..9833b7a --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4e9e340 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1616 @@ +{ + "name": "claude-code-requirements", + "version": "1.2.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "claude-code-requirements", + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.0.0", + "zod": "^3.22.0" + }, + "bin": { + "claude-code-requirements": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "tsx": "^4.0.0", + "typescript": "^5.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.13.2.tgz", + "integrity": "sha512-Vx7qOcmoKkR3qhaQ9qf3GxiVKCEu+zfJddHv6x3dY/9P6+uIwJnmuAur5aB+4FDXf41rRrDnOEGkviX5oYZ67w==", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", + "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.3.tgz", + "integrity": "sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsx": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz", + "integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/zod": { + "version": "3.25.67", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.67.tgz", + "integrity": "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..553c643 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "claude-code-requirements", + "version": "1.2.1", + "description": "MCP server for Claude Code requirements gathering workflow", + "main": "dist/index.js", + "type": "module", + "bin": { + "claude-code-requirements": "dist/index.js" + }, + "scripts": { + "build": "tsc", + "dev": "tsx src/index.ts", + "start": "node dist/index.js", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "mcp", + "claude", + "requirements", + "ai", + "workflow" + ], + "author": "Claude Code Requirements Team", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.0.0", + "zod": "^3.22.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "tsx": "^4.0.0", + "typescript": "^5.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/amittell/claude-code-requirements-builder.git" + }, + "bugs": { + "url": "https://github.com/amittell/claude-code-requirements-builder/issues" + }, + "homepage": "https://github.com/amittell/claude-code-requirements-builder#readme" +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..07e8a2e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,954 @@ +#!/usr/bin/env node + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { z } from "zod"; +import { promises as fs } from "fs"; +import { join, dirname } from "path"; +import { fileURLToPath } from "url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +// Configuration settings +interface ServerSettings { + discoveryQuestions: number; + expertQuestions: number; +} + +const DEFAULT_SETTINGS: ServerSettings = { + discoveryQuestions: 5, + expertQuestions: 5 +}; + +// Load settings from file or use defaults +async function loadSettings(): Promise { + const requirementsDir = join(process.cwd(), 'requirements'); + const settingsPath = join(requirementsDir, '.mcp-settings.json'); + + try { + // Ensure requirements directory exists before reading + await ensureDir(requirementsDir); + const content = await fs.readFile(settingsPath, 'utf-8'); + const parsed = JSON.parse(content); + return { ...DEFAULT_SETTINGS, ...parsed }; + } catch { + // If file doesn't exist or can't be read, return defaults + return DEFAULT_SETTINGS; + } +} + +// Save settings to file +async function saveSettings(settings: ServerSettings): Promise { + const requirementsDir = join(process.cwd(), 'requirements'); + await ensureDir(requirementsDir); + const settingsPath = join(requirementsDir, '.mcp-settings.json'); + await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2)); +} + +// Create the MCP server +const server = new McpServer({ + name: "claude-code-requirements", + version: "1.2.1" +}); + +// Helper functions for file operations +async function ensureDir(dirPath: string): Promise { + try { + await fs.mkdir(dirPath, { recursive: true }); + } catch (error) { + // Directory might already exist + } +} + +async function fileExists(filePath: string): Promise { + try { + await fs.access(filePath); + return true; + } catch { + return false; + } +} + +async function readFileIfExists(filePath: string): Promise { + try { + return await fs.readFile(filePath, 'utf-8'); + } catch { + return null; + } +} + +async function getCurrentRequirement(): Promise { + const currentFile = join(process.cwd(), 'requirements', '.current-requirement'); + return await readFileIfExists(currentFile); +} + +async function setCurrentRequirement(folderName: string): Promise { + const requirementsDir = join(process.cwd(), 'requirements'); + await ensureDir(requirementsDir); + const currentFile = join(requirementsDir, '.current-requirement'); + await fs.writeFile(currentFile, folderName); +} + +async function clearCurrentRequirement(): Promise { + const currentFile = join(process.cwd(), 'requirements', '.current-requirement'); + try { + await fs.unlink(currentFile); + } catch { + // File might not exist + } +} + +function createTimestampFolder(name: string): string { + const now = new Date(); + const timestamp = now.toISOString() + .slice(0, 16) + .replace('T', '-') + .replace(':', ''); + + const slug = name + .toLowerCase() + .replace(/[^a-z0-9\s-]/g, '') + .replace(/\s+/g, '-') + .slice(0, 30); + + return `${timestamp}-${slug}`; +} + +// Tool: requirements-start +server.registerTool( + "requirements-start", + { + title: "Start Requirements Gathering", + description: "Begin gathering requirements for a new feature or project", + inputSchema: { + request: z.string().describe("The feature or project request to gather requirements for") + } + }, + async ({ request }) => { + try { + // Check if there's already an active requirement + const currentRequirement = await getCurrentRequirement(); + if (currentRequirement) { + return { + content: [{ + type: "text", + text: `❌ There is already an active requirement session: ${currentRequirement}\n\nPlease complete it first with 'requirements-end' or check its status with 'requirements-status'.` + }] + }; + } + + // Create timestamped folder + const folderName = createTimestampFolder(request); + const requirementPath = join(process.cwd(), 'requirements', folderName); + await ensureDir(requirementPath); + + // Load settings to determine question counts + const settings = await loadSettings(); + + // Create initial files + const initialRequestContent = `# Initial Request\n\n**Timestamp:** ${new Date().toISOString()}\n\n**Request:** ${request}\n\n---\n\nThis is the starting point for requirements gathering session: ${folderName}\n`; + + const metadata = { + id: folderName.split('-').slice(-1)[0], + started: new Date().toISOString(), + lastUpdated: new Date().toISOString(), + status: "active", + phase: "discovery", + progress: { + discovery: { answered: 0, total: settings.discoveryQuestions }, + detail: { answered: 0, total: settings.expertQuestions } + }, + contextFiles: [], + relatedFeatures: [], + settings: settings + }; + + await fs.writeFile( + join(requirementPath, '00-initial-request.md'), + initialRequestContent + ); + + await fs.writeFile( + join(requirementPath, 'metadata.json'), + JSON.stringify(metadata, null, 2) + ); + + // Set as current requirement + await setCurrentRequirement(folderName); + + // Generate and save discovery questions + const discoveryQuestions = generateDiscoveryQuestions(settings.discoveryQuestions); + const questionsContent = `# Discovery Questions\n\n**Generated:** ${new Date().toISOString()}\n**Total Questions:** ${settings.discoveryQuestions}\n\n` + + discoveryQuestions.map((q, index) => + `## Q${index + 1}: ${q.question}\n**Default if unknown:** ${q.defaultValue ? 'Yes' : 'No'} (${q.reason})\n` + ).join('\n'); + + await fs.writeFile( + join(requirementPath, '01-discovery-questions.md'), + questionsContent + ); + + return { + content: [{ + type: "text", + text: `✅ Requirements gathering started for: "${request}"\n\n📁 Created folder: requirements/${folderName}\n📝 Session is now active\n\n**Settings:**\n- Discovery Questions: ${settings.discoveryQuestions}\n- Expert Questions: ${settings.expertQuestions}\n\n**Next Steps:**\n1. Use 'requirements-status' to continue with discovery questions\n2. The system will guide you through the 5-phase workflow:\n - Phase 1: Setup & Codebase Analysis ✅\n - Phase 2: Context Discovery Questions (${settings.discoveryQuestions} questions)\n - Phase 3: Targeted Context Gathering\n - Phase 4: Expert Requirements Questions (${settings.expertQuestions} questions)\n - Phase 5: Requirements Documentation\n\n**Current Phase:** Discovery - Ready to ask ${settings.discoveryQuestions} yes/no questions` + }] + }; + } catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error starting requirements gathering: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } + } +); + +// Tool: requirements-status +server.registerTool( + "requirements-status", + { + title: "Check Requirements Status and Continue", + description: "Check the status and progress of the current requirements gathering session and continue the workflow", + inputSchema: {} + }, + async () => { + try { + const currentRequirement = await getCurrentRequirement(); + if (!currentRequirement) { + return { + content: [{ + type: "text", + text: `📋 **No Active Requirements Session**\n\nTo start a new requirements gathering session:\n- Use 'requirements-start' with your feature request\n\nTo view previous sessions:\n- Use 'requirements-list' to see all requirements` + }] + }; + } + + const requirementPath = join(process.cwd(), 'requirements', currentRequirement); + const metadataPath = join(requirementPath, 'metadata.json'); + + if (!await fileExists(metadataPath)) { + return { + content: [{ + type: "text", + text: `❌ Metadata file not found for active session: ${currentRequirement}` + }], + isError: true + }; + } + + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + + // If we're in discovery phase and have unanswered questions, continue asking + if (metadata.phase === "discovery" && metadata.progress.discovery.answered < metadata.progress.discovery.total) { + const currentQuestionIndex = metadata.progress.discovery.answered; + const settings = metadata.settings || await loadSettings(); + const discoveryQuestions = generateDiscoveryQuestions(settings.discoveryQuestions); + const currentQuestion = discoveryQuestions[currentQuestionIndex]; + + // Ask the current question using elicitation + const answer = await askQuestion( + server, + `Discovery Question ${currentQuestionIndex + 1}/${metadata.progress.discovery.total}: ${currentQuestion.question}`, + currentQuestion.defaultValue, + currentQuestion.reason + ); + + // Update progress + metadata.progress.discovery.answered++; + metadata.lastUpdated = new Date().toISOString(); + + // Save the answer to the answers file + const answersPath = join(requirementPath, '02-discovery-answers.md'); + let answersContent = ''; + if (await fileExists(answersPath)) { + answersContent = await fs.readFile(answersPath, 'utf-8'); + } else { + answersContent = `# Discovery Answers\n\n**Started:** ${new Date().toISOString()}\n\n`; + } + + answersContent += `## Q${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n**Reasoning:** ${currentQuestion.reason}\n\n`; + + await fs.writeFile(answersPath, answersContent); + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + + // Check if discovery phase is complete + if (metadata.progress.discovery.answered >= metadata.progress.discovery.total) { + metadata.phase = "context"; + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + + return { + content: [{ + type: "text", + text: `✅ **Discovery Phase Complete!**\n\nAnswered: ${answer ? 'Yes' : 'No'} to "${currentQuestion.question}"\n\n🎉 All ${metadata.progress.discovery.total} discovery questions completed!\n\n**Next Phase:** Context Gathering\n- The system will now analyze the codebase based on your answers\n- Use 'requirements-status' again to continue to expert questions` + }] + }; + } else { + return { + content: [{ + type: "text", + text: `✅ **Question Answered**\n\nQ${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n\n**Progress:** ${metadata.progress.discovery.answered}/${metadata.progress.discovery.total} discovery questions completed\n\nUse 'requirements-status' again to continue with the next question.` + }] + }; + } + } + + // If in context phase, move to detail questions + if (metadata.phase === "context") { + metadata.phase = "detail"; + metadata.lastUpdated = new Date().toISOString(); + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + + return { + content: [{ + type: "text", + text: `📋 **Context Phase Complete**\n\nMoving to Expert Questions phase...\n\n**Next:** ${metadata.progress.detail.total} expert questions about system behavior\n\nUse 'requirements-status' again to start expert questions.` + }] + }; + } + + // If we're in detail phase and have unanswered questions, continue asking + if (metadata.phase === "detail" && metadata.progress.detail.answered < metadata.progress.detail.total) { + const currentQuestionIndex = metadata.progress.detail.answered; + + // For now, use basic expert questions - in a full implementation, these would be generated based on context analysis + const expertQuestions = [ + { + question: "Should this feature be accessible to all user roles?", + defaultValue: false, + reason: "role-based access is more common for new features" + }, + { + question: "Will this feature require database schema changes?", + defaultValue: true, + reason: "most new features need new data structures" + }, + { + question: "Should this feature have comprehensive error handling and validation?", + defaultValue: true, + reason: "robust error handling is a best practice" + }, + { + question: "Will this feature need to be backwards compatible with existing APIs?", + defaultValue: true, + reason: "maintaining API compatibility is usually required" + }, + { + question: "Should this feature include comprehensive logging and monitoring?", + defaultValue: true, + reason: "observability is critical for production features" + } + ].slice(0, metadata.progress.detail.total); + + const currentQuestion = expertQuestions[currentQuestionIndex]; + + // Ask the current expert question using elicitation + const answer = await askQuestion( + server, + `Expert Question ${currentQuestionIndex + 1}/${metadata.progress.detail.total}: ${currentQuestion.question}`, + currentQuestion.defaultValue, + currentQuestion.reason + ); + + // Update progress + metadata.progress.detail.answered++; + metadata.lastUpdated = new Date().toISOString(); + + // Save the answer to the detail answers file + const detailAnswersPath = join(requirementPath, '05-detail-answers.md'); + let detailAnswersContent = ''; + if (await fileExists(detailAnswersPath)) { + detailAnswersContent = await fs.readFile(detailAnswersPath, 'utf-8'); + } else { + detailAnswersContent = `# Expert Question Answers\n\n**Started:** ${new Date().toISOString()}\n\n`; + } + + detailAnswersContent += `## Q${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n**Reasoning:** ${currentQuestion.reason}\n\n`; + + await fs.writeFile(detailAnswersPath, detailAnswersContent); + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + + // Check if detail phase is complete + if (metadata.progress.detail.answered >= metadata.progress.detail.total) { + metadata.phase = "complete"; + metadata.status = "completed"; + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + + return { + content: [{ + type: "text", + text: `✅ **Expert Questions Complete!**\n\nAnswered: ${answer ? 'Yes' : 'No'} to "${currentQuestion.question}"\n\n🎉 All ${metadata.progress.detail.total} expert questions completed!\n\n**Status:** Requirements gathering complete\n**Next:** Use 'requirements-end' to finalize the session\n\nAll answers have been saved and the requirements specification can now be generated.` + }] + }; + } else { + return { + content: [{ + type: "text", + text: `✅ **Expert Question Answered**\n\nQ${currentQuestionIndex + 1}: ${currentQuestion.question}\n**Answer:** ${answer ? 'Yes' : 'No'}\n\n**Progress:** ${metadata.progress.detail.answered}/${metadata.progress.detail.total} expert questions completed\n\nUse 'requirements-status' again to continue with the next question.` + }] + }; + } + } + + // Show status for completed or other phases + const phaseDescriptions: Record = { + discovery: "Context Discovery Questions (understanding problem space)", + context: "Targeted Context Gathering (autonomous codebase analysis)", + detail: "Expert Requirements Questions (detailed system behavior)", + complete: "Requirements Documentation (comprehensive spec generation)" + }; + + let statusText = `📋 **Requirements Session Status**\n\n`; + statusText += `**Session:** ${currentRequirement}\n`; + statusText += `**Started:** ${new Date(metadata.started).toLocaleString()}\n`; + statusText += `**Last Updated:** ${new Date(metadata.lastUpdated).toLocaleString()}\n`; + statusText += `**Status:** ${metadata.status}\n`; + statusText += `**Current Phase:** ${metadata.phase} - ${phaseDescriptions[metadata.phase] || 'Unknown'}\n\n`; + + statusText += `**Progress:**\n`; + if (metadata.progress.discovery) { + statusText += `- Discovery Questions: ${metadata.progress.discovery.answered}/${metadata.progress.discovery.total} answered\n`; + } + if (metadata.progress.detail) { + statusText += `- Expert Questions: ${metadata.progress.detail.answered}/${metadata.progress.detail.total} answered\n`; + } + + if (metadata.contextFiles && metadata.contextFiles.length > 0) { + statusText += `\n**Analyzed Files:** ${metadata.contextFiles.length} files\n`; + } + + statusText += `\n**Available Actions:**\n`; + statusText += `- 'requirements-current' - View detailed session info\n`; + statusText += `- 'requirements-end' - Complete or cancel session\n`; + + return { + content: [{ + type: "text", + text: statusText + }] + }; + } catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error checking requirements status: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } + } +); + +// Tool: requirements-current +server.registerTool( + "requirements-current", + { + title: "View Current Requirements Details", + description: "View detailed information about the current requirements gathering session", + inputSchema: {} + }, + async () => { + try { + const currentRequirement = await getCurrentRequirement(); + if (!currentRequirement) { + return { + content: [{ + type: "text", + text: `📋 No active requirements session. Use 'requirements-start' to begin.` + }] + }; + } + + const requirementPath = join(process.cwd(), 'requirements', currentRequirement); + + // Read all relevant files + const files = await fs.readdir(requirementPath); + const mdFiles = files.filter(f => f.endsWith('.md')).sort(); + + let content = `📋 **Current Requirements Session: ${currentRequirement}**\n\n`; + + // Show each file content + for (const file of mdFiles) { + const filePath = join(requirementPath, file); + const fileContent = await fs.readFile(filePath, 'utf-8'); + + content += `## ${file}\n\n`; + content += `${fileContent}\n\n---\n\n`; + } + + // Show metadata + const metadataPath = join(requirementPath, 'metadata.json'); + if (await fileExists(metadataPath)) { + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + + content += `## Metadata\n\n`; + content += `\`\`\`json\n${JSON.stringify(metadata, null, 2)}\n\`\`\`\n`; + } + + return { + content: [{ + type: "text", + text: content + }] + }; + } catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error viewing current requirements: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } + } +); + +// Tool: requirements-end +server.registerTool( + "requirements-end", + { + title: "End Requirements Session", + description: "Complete, mark as incomplete, or delete the current requirements gathering session", + inputSchema: { + action: z.enum(["complete", "incomplete", "delete"]).describe("Action to take: complete (mark as finished), incomplete (save but mark unfinished), delete (remove entirely)") + } + }, + async ({ action }) => { + try { + const currentRequirement = await getCurrentRequirement(); + if (!currentRequirement) { + return { + content: [{ + type: "text", + text: `❌ No active requirements session to end.` + }] + }; + } + + const requirementPath = join(process.cwd(), 'requirements', currentRequirement); + const metadataPath = join(requirementPath, 'metadata.json'); + + if (action === "delete") { + // Delete the entire requirement folder + await fs.rm(requirementPath, { recursive: true, force: true }); + await clearCurrentRequirement(); + + return { + content: [{ + type: "text", + text: `🗑️ **Requirements session deleted**\n\nDeleted: ${currentRequirement}\nNo active session remaining.` + }] + }; + } + + // Update metadata for complete/incomplete + if (await fileExists(metadataPath)) { + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + + metadata.status = action === "complete" ? "completed" : "incomplete"; + metadata.lastUpdated = new Date().toISOString(); + metadata.endedAt = new Date().toISOString(); + + await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2)); + } + + // Update requirements index + const indexPath = join(process.cwd(), 'requirements', 'index.md'); + const indexExists = await fileExists(indexPath); + + let indexContent = indexExists ? await fs.readFile(indexPath, 'utf-8') : + `# Requirements Index\n\nThis file tracks all requirements gathering sessions.\n\n`; + + const statusEmoji = action === "complete" ? "✅" : "⚠️"; + const statusText = action === "complete" ? "Completed" : "Incomplete"; + const newEntry = `- ${statusEmoji} **${currentRequirement}** - ${statusText} (${new Date().toLocaleDateString()})\n`; + + if (!indexContent.includes(currentRequirement)) { + indexContent += newEntry; + await fs.writeFile(indexPath, indexContent); + } + + await clearCurrentRequirement(); + + return { + content: [{ + type: "text", + text: `${statusEmoji} **Requirements session ${action === "complete" ? "completed" : "marked incomplete"}**\n\nSession: ${currentRequirement}\nStatus: ${statusText}\nNo active session remaining.\n\nUse 'requirements-list' to view all sessions.` + }] + }; + } catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error ending requirements session: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } + } +); + +// Tool: requirements-list +server.registerTool( + "requirements-list", + { + title: "List All Requirements", + description: "List all requirements gathering sessions (active and completed)", + inputSchema: {} + }, + async () => { + try { + const requirementsDir = join(process.cwd(), 'requirements'); + + if (!await fileExists(requirementsDir)) { + return { + content: [{ + type: "text", + text: `📋 **No Requirements Sessions Found**\n\nThe requirements/ directory doesn't exist yet.\nUse 'requirements-start' to create your first session.` + }] + }; + } + + const entries = await fs.readdir(requirementsDir, { withFileTypes: true }); + const folders = entries.filter(entry => entry.isDirectory()).map(entry => entry.name); + + if (folders.length === 0) { + return { + content: [{ + type: "text", + text: `📋 **No Requirements Sessions Found**\n\nUse 'requirements-start' to create your first session.` + }] + }; + } + + const currentRequirement = await getCurrentRequirement(); + let content = `📋 **All Requirements Sessions**\n\n`; + + // Sort folders by timestamp (newest first) + const sortedFolders = folders.sort().reverse(); + + for (const folder of sortedFolders) { + const folderPath = join(requirementsDir, folder); + const metadataPath = join(folderPath, 'metadata.json'); + + let status = "Unknown"; + let phase = "Unknown"; + let started = "Unknown"; + + if (await fileExists(metadataPath)) { + try { + const metadataContent = await fs.readFile(metadataPath, 'utf-8'); + const metadata = JSON.parse(metadataContent); + status = metadata.status || "Unknown"; + phase = metadata.phase || "Unknown"; + started = metadata.started ? new Date(metadata.started).toLocaleDateString() : "Unknown"; + } catch { + // Ignore metadata read errors + } + } + + const isActive = folder === currentRequirement; + const activeIndicator = isActive ? " 🟢 **ACTIVE**" : ""; + const statusEmoji = status === "completed" ? "✅" : status === "incomplete" ? "⚠️" : status === "active" ? "🟡" : "❓"; + + content += `${statusEmoji} **${folder}**${activeIndicator}\n`; + content += ` Status: ${status} | Phase: ${phase} | Started: ${started}\n\n`; + } + + content += `**Actions:**\n`; + content += `- 'requirements-start' - Start new session\n`; + if (currentRequirement) { + content += `- 'requirements-status' - Check active session\n`; + content += `- 'requirements-current' - View active session details\n`; + } + + return { + content: [{ + type: "text", + text: content + }] + }; + } catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error listing requirements: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } + } +); + +// Tool: requirements-remind +server.registerTool( + "requirements-remind", + { + title: "Workflow Reminder", + description: "Get a reminder of the requirements gathering workflow rules and best practices", + inputSchema: {} + }, + async () => { + const reminderContent = `📚 **Requirements Gathering Workflow Reminder** + +## 5-Phase Workflow: + +### Phase 1: Initial Setup & Codebase Analysis +- Create timestamp-based folder +- Extract slug from request +- Create initial files (00-initial-request.md, metadata.json) +- Set as current requirement +- Analyze overall codebase structure + +### Phase 2: Context Discovery Questions +- Generate 5 most important yes/no questions about problem space +- Questions about user interactions, workflows, similar features +- Questions about data/content, integrations, performance +- Write ALL questions to 01-discovery-questions.md with smart defaults +- Ask questions ONE AT A TIME +- Record answers in 02-discovery-answers.md + +### Phase 3: Targeted Context Gathering (Autonomous) +- Search for specific files based on discovery answers +- Deep dive into similar features and patterns +- Analyze implementation details +- Document findings in 03-context-findings.md with: + - Specific files that need modification + - Exact patterns to follow + - Technical constraints and considerations + +### Phase 4: Expert Requirements Questions +- Ask 5 detailed yes/no questions like a senior developer +- Questions about expected system behavior using codebase knowledge +- Include smart defaults based on codebase patterns +- Write to 04-detail-questions.md, ask one at a time +- Record answers in 05-detail-answers.md + +### Phase 5: Requirements Documentation +- Generate comprehensive spec in 06-requirements-spec.md: + - Problem statement and solution overview + - Functional requirements based on all answers + - Technical requirements with specific file paths + - Implementation hints and patterns + - Acceptance criteria + - Assumptions for unanswered questions + +## Key Rules: +- **ONLY yes/no questions** with smart defaults +- **ONE question at a time** (never batch) +- **Write ALL questions to file BEFORE asking any** +- Use actual file paths and component names in detail phase +- Document WHY each default makes sense +- Stay focused on requirements (no implementation) + +## Current Status: +Use 'requirements-status' to see your current phase and progress.`; + + return { + content: [{ + type: "text", + text: reminderContent + }] + }; + } +); + +// Tool: requirements-settings +server.registerTool( + "requirements-settings", + { + title: "Configure Requirements Settings", + description: "Interactively configure the number of discovery and expert questions", + inputSchema: {} + }, + async () => { + try { + const currentSettings = await loadSettings(); + + // Show current settings first + let resultMessage = `📋 **Current Settings**\n\n**Discovery Questions:** ${currentSettings.discoveryQuestions}\n**Expert Questions:** ${currentSettings.expertQuestions}\n\n`; + + // Ask for discovery questions count + const discoveryResult = await server.server.elicitInput({ + message: `Discovery Questions (current: ${currentSettings.discoveryQuestions})`, + requestedSchema: { + type: "object", + properties: { + count: { + type: "number", + title: "Number of Discovery Questions", + description: `Current: ${currentSettings.discoveryQuestions}. Press Enter to keep current value, or enter a number between 1-20`, + default: currentSettings.discoveryQuestions, + minimum: 1, + maximum: 20 + } + }, + required: ["count"] + } + }); + + const newDiscoveryCount = (discoveryResult.action === "accept" && discoveryResult.content?.count) + ? discoveryResult.content.count as number + : currentSettings.discoveryQuestions; + + // Ask for expert questions count + const expertResult = await server.server.elicitInput({ + message: `Expert Questions (current: ${currentSettings.expertQuestions})`, + requestedSchema: { + type: "object", + properties: { + count: { + type: "number", + title: "Number of Expert Questions", + description: `Current: ${currentSettings.expertQuestions}. Press Enter to keep current value, or enter a number between 1-20`, + default: currentSettings.expertQuestions, + minimum: 1, + maximum: 20 + } + }, + required: ["count"] + } + }); + + const newExpertCount = (expertResult.action === "accept" && expertResult.content?.count) + ? expertResult.content.count as number + : currentSettings.expertQuestions; + + // Check if anything changed + if (newDiscoveryCount === currentSettings.discoveryQuestions && newExpertCount === currentSettings.expertQuestions) { + return { + content: [{ + type: "text", + text: `📋 **Settings Unchanged**\n\n**Discovery Questions:** ${currentSettings.discoveryQuestions}\n**Expert Questions:** ${currentSettings.expertQuestions}\n\nNo changes were made to the settings.` + }] + }; + } + + // Save new settings + const newSettings: ServerSettings = { + discoveryQuestions: newDiscoveryCount, + expertQuestions: newExpertCount + }; + + await saveSettings(newSettings); + + return { + content: [{ + type: "text", + text: `✅ **Settings Updated**\n\n**Discovery Questions:** ${newSettings.discoveryQuestions} ${newSettings.discoveryQuestions !== currentSettings.discoveryQuestions ? '(changed)' : ''}\n**Expert Questions:** ${newSettings.expertQuestions} ${newSettings.expertQuestions !== currentSettings.expertQuestions ? '(changed)' : ''}\n\nSettings saved to requirements/.mcp-settings.json` + }] + }; + + } catch (error) { + return { + content: [{ + type: "text", + text: `❌ Error managing settings: ${error instanceof Error ? error.message : 'Unknown error'}` + }], + isError: true + }; + } + } +); + +// Helper function to ask a single question using elicitation +async function askQuestion( + mcpServer: McpServer, + questionText: string, + defaultValue: boolean, + defaultReason: string +): Promise { + const result = await mcpServer.server.elicitInput({ + message: questionText, + requestedSchema: { + type: "object", + properties: { + answer: { + type: "boolean", + title: "Answer", + description: `Default: ${defaultValue ? 'Yes' : 'No'} (${defaultReason})`, + default: defaultValue + } + }, + required: ["answer"] + } + }); + + if (result.action === "accept" && result.content?.answer !== undefined) { + return result.content.answer as boolean; + } + + // If user cancels or rejects, use default + return defaultValue; +} + +// Helper function to generate discovery questions +function generateDiscoveryQuestions(count: number): Array<{question: string, defaultValue: boolean, reason: string}> { + const allQuestions = [ + { + question: "Will users interact with this feature through a visual interface?", + defaultValue: true, + reason: "most features have some UI component" + }, + { + question: "Does this feature need to work on mobile devices?", + defaultValue: true, + reason: "mobile-first is standard practice" + }, + { + question: "Will this feature handle sensitive or private user data?", + defaultValue: true, + reason: "better to be secure by default" + }, + { + question: "Do users currently have a workaround for this problem?", + defaultValue: false, + reason: "assuming this solves a new need" + }, + { + question: "Will this feature need to work offline?", + defaultValue: false, + reason: "most features require connectivity" + }, + { + question: "Will this feature require real-time updates or notifications?", + defaultValue: false, + reason: "real-time features add complexity" + }, + { + question: "Does this feature need to integrate with external APIs or services?", + defaultValue: false, + reason: "internal features are more common" + }, + { + question: "Will this feature need to scale to handle many concurrent users?", + defaultValue: true, + reason: "better to plan for scale upfront" + }, + { + question: "Does this feature require user authentication or authorization?", + defaultValue: true, + reason: "most features need some level of access control" + }, + { + question: "Will this feature need to maintain audit logs or activity history?", + defaultValue: false, + reason: "audit logs are typically for specific use cases" + } + ]; + + return allQuestions.slice(0, count); +} + +// Connect the server +async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); +} + +main().catch(console.error); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4285c2f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "resolveJsonModule": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist", + "**/*.test.ts" + ] +} \ No newline at end of file