diff --git a/.changeset/curly-months-go.md b/.changeset/curly-months-go.md new file mode 100644 index 00000000..3213f618 --- /dev/null +++ b/.changeset/curly-months-go.md @@ -0,0 +1,5 @@ +--- +"task-master-ai": patch +--- + +Fix bedrock issues diff --git a/.changeset/loud-dolls-yell.md b/.changeset/loud-dolls-yell.md new file mode 100644 index 00000000..4cc1ae18 --- /dev/null +++ b/.changeset/loud-dolls-yell.md @@ -0,0 +1,5 @@ +--- +"task-master-ai": patch +--- + +Update rules for new directory structure diff --git a/.changeset/tall-symbols-call.md b/.changeset/tall-symbols-call.md new file mode 100644 index 00000000..a6087653 --- /dev/null +++ b/.changeset/tall-symbols-call.md @@ -0,0 +1,5 @@ +--- +"task-master-ai": patch +--- + +Fix MCP crashing after certain commands due to console logs diff --git a/.taskmaster/config.json b/.taskmaster/config.json index 83cedf70..a61d10d5 100644 --- a/.taskmaster/config.json +++ b/.taskmaster/config.json @@ -26,6 +26,7 @@ "defaultPriority": "medium", "projectName": "Taskmaster", "ollamaBaseURL": "http://localhost:11434/api", + "bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com", "userId": "1234567890", "azureBaseURL": "https://your-endpoint.azure.com/" } diff --git a/.taskmasterconfig b/.taskmasterconfig deleted file mode 100644 index 83cedf70..00000000 --- a/.taskmasterconfig +++ /dev/null @@ -1,32 +0,0 @@ -{ - "models": { - "main": { - "provider": "anthropic", - "modelId": "claude-sonnet-4-20250514", - "maxTokens": 50000, - "temperature": 0.2 - }, - "research": { - "provider": "perplexity", - "modelId": "sonar-pro", - "maxTokens": 8700, - "temperature": 0.1 - }, - "fallback": { - "provider": "anthropic", - "modelId": "claude-3-7-sonnet-20250219", - "maxTokens": 128000, - "temperature": 0.2 - } - }, - "global": { - "logLevel": "info", - "debug": false, - "defaultSubtasks": 5, - "defaultPriority": "medium", - "projectName": "Taskmaster", - "ollamaBaseURL": "http://localhost:11434/api", - "userId": "1234567890", - "azureBaseURL": "https://your-endpoint.azure.com/" - } -} diff --git a/assets/AGENTS.md b/assets/AGENTS.md index 4e43ccf7..83f3f786 100644 --- a/assets/AGENTS.md +++ b/assets/AGENTS.md @@ -56,20 +56,24 @@ task-master generate # Update task markd ``` project/ -├── tasks/ -│ ├── tasks.json # Main task database -│ ├── task-1.md # Individual task files -│ └── task-2.md -├── scripts/ -│ ├── prd.txt # Product requirements -│ └── task-complexity-report.json +├── .taskmaster/ +│ ├── tasks/ # Task files directory +│ │ ├── tasks.json # Main task database +│ │ ├── task-1.md # Individual task files +│ │ └── task-2.md +│ ├── docs/ # Documentation directory +│ │ ├── prd.txt # Product requirements +│ ├── reports/ # Analysis reports directory +│ │ └── task-complexity-report.json +│ ├── templates/ # Template files +│ │ └── example_prd.txt # Example PRD template +│ └── config.json # AI models & settings ├── .claude/ -│ ├── settings.json # Claude Code configuration -│ └── commands/ # Custom slash commands -├── .taskmasterconfig # AI models & settings -├── .env # API keys -├── .mcp.json # MCP configuration -└── CLAUDE.md # This file - auto-loaded by Claude Code +│ ├── settings.json # Claude Code configuration +│ └── commands/ # Custom slash commands +├── .env # API keys +├── .mcp.json # MCP configuration +└── CLAUDE.md # This file - auto-loaded by Claude Code ``` ## MCP Integration @@ -384,7 +388,7 @@ These commands make AI calls and may take up to a minute: ### File Management - Never manually edit `tasks.json` - use commands instead -- Never manually edit `.taskmasterconfig` - use `task-master models` +- Never manually edit `.taskmaster/config.json` - use `task-master models` - Task markdown files in `tasks/` are auto-generated - Run `task-master generate` after manual changes to tasks.json diff --git a/assets/.taskmasterconfig b/assets/config.json similarity index 91% rename from assets/.taskmasterconfig rename to assets/config.json index 907f4290..8385534a 100644 --- a/assets/.taskmasterconfig +++ b/assets/config.json @@ -26,6 +26,7 @@ "defaultPriority": "medium", "projectName": "Taskmaster", "ollamaBaseURL": "http://localhost:11434/api", - "azureOpenaiBaseURL": "https://your-endpoint.openai.azure.com/" + "azureOpenaiBaseURL": "https://your-endpoint.openai.azure.com/", + "bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com" } } diff --git a/assets/env.example b/assets/env.example index c7142879..41a8faec 100644 --- a/assets/env.example +++ b/assets/env.example @@ -5,5 +5,5 @@ OPENAI_API_KEY="your_openai_api_key_here" # Optional, for OpenAI/Ope GOOGLE_API_KEY="your_google_api_key_here" # Optional, for Google Gemini models. MISTRAL_API_KEY="your_mistral_key_here" # Optional, for Mistral AI models. XAI_API_KEY="YOUR_XAI_KEY_HERE" # Optional, for xAI AI models. -AZURE_OPENAI_API_KEY="your_azure_key_here" # Optional, for Azure OpenAI models (requires endpoint in .taskmasterconfig). +AZURE_OPENAI_API_KEY="your_azure_key_here" # Optional, for Azure OpenAI models (requires endpoint in .taskmaster/config.json). OLLAMA_API_KEY="your_ollama_api_key_here" # Optional: For remote Ollama servers that require authentication. \ No newline at end of file diff --git a/assets/scripts_README.md b/assets/scripts_README.md index 1e76856f..dea4c585 100644 --- a/assets/scripts_README.md +++ b/assets/scripts_README.md @@ -20,7 +20,7 @@ In an AI-driven development process—particularly with tools like [Cursor](http Task Master configuration is now managed through two primary methods: -1. **`.taskmasterconfig` File (Project Root - Primary)** +1. **`.taskmaster/config.json` File (Project Root - Primary)** - Stores AI model selections (`main`, `research`, `fallback`), model parameters (`maxTokens`, `temperature`), `logLevel`, `defaultSubtasks`, `defaultPriority`, `projectName`, etc. - Managed using the `task-master models --setup` command or the `models` MCP tool. @@ -192,7 +192,7 @@ Notes: ## AI Integration (Updated) - The script now uses a unified AI service layer (`ai-services-unified.js`). -- Model selection (e.g., Claude vs. Perplexity for `--research`) is determined by the configuration in `.taskmasterconfig` based on the requested `role` (`main` or `research`). +- Model selection (e.g., Claude vs. Perplexity for `--research`) is determined by the configuration in `.taskmaster/config.json` based on the requested `role` (`main` or `research`). - API keys are automatically resolved from your `.env` file (for CLI) or MCP session environment. - To use the research capabilities (e.g., `expand --research`), ensure you have: 1. Configured a model for the `research` role using `task-master models --setup` (Perplexity models are recommended). @@ -357,25 +357,25 @@ The output report structure is: ```json { - "meta": { - "generatedAt": "2023-06-15T12:34:56.789Z", - "tasksAnalyzed": 20, - "thresholdScore": 5, - "projectName": "Your Project Name", - "usedResearch": true - }, - "complexityAnalysis": [ - { - "taskId": 8, - "taskTitle": "Develop Implementation Drift Handling", - "complexityScore": 9.5, - "recommendedSubtasks": 6, - "expansionPrompt": "Create subtasks that handle detecting...", - "reasoning": "This task requires sophisticated logic...", - "expansionCommand": "task-master expand --id=8 --num=6 --prompt=\"Create subtasks...\" --research" - } - // More tasks sorted by complexity score (highest first) - ] + "meta": { + "generatedAt": "2023-06-15T12:34:56.789Z", + "tasksAnalyzed": 20, + "thresholdScore": 5, + "projectName": "Your Project Name", + "usedResearch": true + }, + "complexityAnalysis": [ + { + "taskId": 8, + "taskTitle": "Develop Implementation Drift Handling", + "complexityScore": 9.5, + "recommendedSubtasks": 6, + "expansionPrompt": "Create subtasks that handle detecting...", + "reasoning": "This task requires sophisticated logic...", + "expansionCommand": "task-master expand --id=8 --num=6 --prompt=\"Create subtasks...\" --research" + } + // More tasks sorted by complexity score (highest first) + ] } ``` diff --git a/mcp-server/src/tools/models.js b/mcp-server/src/tools/models.js index 3267ee65..3eb71877 100644 --- a/mcp-server/src/tools/models.js +++ b/mcp-server/src/tools/models.js @@ -47,7 +47,6 @@ export function registerModelsTool(server) { ), projectRoot: z .string() - .optional() .describe('The directory of the project. Must be an absolute path.'), openrouter: z .boolean() diff --git a/mcp-server/src/tools/parse-prd.js b/mcp-server/src/tools/parse-prd.js index 18c6b7f7..421402cf 100644 --- a/mcp-server/src/tools/parse-prd.js +++ b/mcp-server/src/tools/parse-prd.js @@ -32,7 +32,6 @@ export function registerParsePRDTool(server) { .describe('Absolute path to the PRD document file (.txt, .md, etc.)'), projectRoot: z .string() - .optional() .describe('The directory of the project. Must be an absolute path.'), output: z .string() diff --git a/scripts/init.js b/scripts/init.js index 4cb3b272..5db49c35 100755 --- a/scripts/init.js +++ b/scripts/init.js @@ -509,9 +509,9 @@ function createProjectStructure(addAliases, dryRun, options) { replacements ); - // Copy .taskmasterconfig with project name to NEW location + // Copy config.json with project name to NEW location copyTemplateFile( - '.taskmasterconfig', + 'config.json', path.join(targetDir, TASKMASTER_CONFIG_FILE), { ...replacements diff --git a/scripts/modules/ai-services-unified.js b/scripts/modules/ai-services-unified.js index 59cde801..ca702701 100644 --- a/scripts/modules/ai-services-unified.js +++ b/scripts/modules/ai-services-unified.js @@ -22,6 +22,7 @@ import { isApiKeySet, getOllamaBaseURL, getAzureBaseURL, + getBedrockBaseURL, getVertexProjectId, getVertexLocation } from './config-manager.js'; @@ -410,6 +411,10 @@ async function _unifiedServiceRunner(serviceType, params) { // For Ollama, use the global Ollama base URL if role-specific URL is not configured baseURL = getOllamaBaseURL(effectiveProjectRoot); log('debug', `Using global Ollama base URL: ${baseURL}`); + } else if (providerName?.toLowerCase() === 'bedrock' && !baseURL) { + // For Bedrock, use the global Bedrock base URL if role-specific URL is not configured + baseURL = getBedrockBaseURL(effectiveProjectRoot); + log('debug', `Using global Bedrock base URL: ${baseURL}`); } // Get AI parameters for the current role diff --git a/scripts/modules/config-manager.js b/scripts/modules/config-manager.js index 1ca4734b..c4a52f70 100644 --- a/scripts/modules/config-manager.js +++ b/scripts/modules/config-manager.js @@ -61,7 +61,8 @@ const DEFAULTS = { defaultSubtasks: 5, defaultPriority: 'medium', projectName: 'Task Master', - ollamaBaseURL: 'http://localhost:11434/api' + ollamaBaseURL: 'http://localhost:11434/api', + bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com' } }; @@ -382,6 +383,11 @@ function getAzureBaseURL(explicitRoot = null) { return getGlobalConfig(explicitRoot).azureBaseURL; } +function getBedrockBaseURL(explicitRoot = null) { + // Directly return value from config + return getGlobalConfig(explicitRoot).bedrockBaseURL; +} + /** * Gets the Google Cloud project ID for Vertex AI from configuration * @param {string|null} explicitRoot - Optional explicit path to the project root. @@ -779,6 +785,7 @@ export { getProjectName, getOllamaBaseURL, getAzureBaseURL, + getBedrockBaseURL, getParametersForRole, getUserId, // API Key Checkers (still relevant) diff --git a/scripts/modules/task-manager/models.js b/scripts/modules/task-manager/models.js index f7aa57f0..8416c616 100644 --- a/scripts/modules/task-manager/models.js +++ b/scripts/modules/task-manager/models.js @@ -482,6 +482,11 @@ async function setModel(role, modelId, options = {}) { `Model ID "${modelId}" not found in the Ollama instance. Please verify the model is pulled and available. You can check available models with: curl ${tagsUrl}` ); } + } else if (providerHint === 'bedrock') { + // Set provider without model validation since Bedrock models are managed by AWS + determinedProvider = 'bedrock'; + warningMessage = `Warning: Custom Bedrock model '${modelId}' set. Please ensure the model ID is valid and accessible in your AWS account.`; + report('warn', warningMessage); } else { // Invalid provider hint - should not happen throw new Error(`Invalid provider hint received: ${providerHint}`); diff --git a/scripts/modules/ui.js b/scripts/modules/ui.js index ca60d42b..5dad1795 100644 --- a/scripts/modules/ui.js +++ b/scripts/modules/ui.js @@ -24,7 +24,10 @@ import { } from './task-manager.js'; import { getProjectName, getDefaultSubtasks } from './config-manager.js'; import { TASK_STATUS_OPTIONS } from '../../src/constants/task-status.js'; -import { TASKMASTER_TASKS_FILE } from '../../src/constants/paths.js'; +import { + TASKMASTER_CONFIG_FILE, + TASKMASTER_TASKS_FILE +} from '../../src/constants/paths.js'; import { getTaskMasterVersion } from '../../src/utils/getVersion.js'; // Create a color gradient for the banner @@ -692,7 +695,7 @@ function displayHelp() { configTable.push( [ - `${chalk.yellow('.taskmasterconfig')}${chalk.reset('')}`, + `${chalk.yellow(TASKMASTER_CONFIG_FILE)}${chalk.reset('')}`, `${chalk.white('AI model configuration file (project root)')}${chalk.reset('')}`, `${chalk.dim('Managed by models cmd')}${chalk.reset('')}` ], @@ -1856,7 +1859,7 @@ function displayApiKeyStatus(statusReport) { console.log(table.toString()); console.log( chalk.gray( - ' Note: Some providers (e.g., Azure, Ollama) may require additional endpoint configuration in .taskmasterconfig.' + ` Note: Some providers (e.g., Azure, Ollama) may require additional endpoint configuration in ${TASKMASTER_CONFIG_FILE}.` ) ); } diff --git a/src/utils/logger-utils.js b/src/utils/logger-utils.js new file mode 100644 index 00000000..70dcfaf3 --- /dev/null +++ b/src/utils/logger-utils.js @@ -0,0 +1,31 @@ +/** + * Logger utility functions for Task Master + * Provides standardized logging patterns for both CLI and utility contexts + */ + +import { log as utilLog } from '../../scripts/modules/utils.js'; + +/** + * Creates a standard logger object that wraps the utility log function + * This provides a consistent logger interface across different parts of the application + * @returns {Object} A logger object with standard logging methods (info, warn, error, debug, success) + */ +export function createStandardLogger() { + return { + info: (msg, ...args) => utilLog('info', msg, ...args), + warn: (msg, ...args) => utilLog('warn', msg, ...args), + error: (msg, ...args) => utilLog('error', msg, ...args), + debug: (msg, ...args) => utilLog('debug', msg, ...args), + success: (msg, ...args) => utilLog('success', msg, ...args) + }; +} + +/** + * Creates a logger using either the provided logger or a default standard logger + * This is the recommended pattern for functions that accept an optional logger parameter + * @param {Object|null} providedLogger - Optional logger object passed from caller + * @returns {Object} A logger object with standard logging methods + */ +export function getLoggerOrDefault(providedLogger = null) { + return providedLogger || createStandardLogger(); +} diff --git a/src/utils/path-utils.js b/src/utils/path-utils.js index a21bfe4e..b06cd7db 100644 --- a/src/utils/path-utils.js +++ b/src/utils/path-utils.js @@ -14,6 +14,7 @@ import { TASKMASTER_CONFIG_FILE, LEGACY_CONFIG_FILE } from '../constants/paths.js'; +import { getLoggerOrDefault } from './logger-utils.js'; /** * Find the project root directory by looking for project markers @@ -59,7 +60,8 @@ export function findProjectRoot(startDir = process.cwd()) { * @returns {string|null} - Resolved tasks.json path or null if not found */ export function findTasksPath(explicitPath = null, args = null, log = null) { - const logger = log || console; + // Use the passed logger if available, otherwise use the default logger + const logger = getLoggerOrDefault(log); // 1. If explicit path is provided, use it (highest priority) if (explicitPath) { @@ -130,7 +132,7 @@ export function findTasksPath(explicitPath = null, args = null, log = null) { * @returns {string|null} - Resolved PRD document path or null if not found */ export function findPRDPath(explicitPath = null, args = null, log = null) { - const logger = log || console; + const logger = getLoggerOrDefault(log); // 1. If explicit path is provided, use it (highest priority) if (explicitPath) { @@ -199,7 +201,7 @@ export function findComplexityReportPath( args = null, log = null ) { - const logger = log || console; + const logger = getLoggerOrDefault(log); // 1. If explicit path is provided, use it (highest priority) if (explicitPath) { @@ -268,7 +270,7 @@ export function resolveTasksOutputPath( args = null, log = null ) { - const logger = log || console; + const logger = getLoggerOrDefault(log); // 1. If explicit path is provided, use it if (explicitPath) { @@ -309,7 +311,7 @@ export function resolveComplexityReportOutputPath( args = null, log = null ) { - const logger = log || console; + const logger = getLoggerOrDefault(log); // 1. If explicit path is provided, use it if (explicitPath) { @@ -348,7 +350,7 @@ export function resolveComplexityReportOutputPath( * @returns {string|null} - Resolved config file path or null if not found */ export function findConfigPath(explicitPath = null, args = null, log = null) { - const logger = log || console; + const logger = getLoggerOrDefault(log); // 1. If explicit path is provided, use it (highest priority) if (explicitPath) { diff --git a/tests/unit/ai-services-unified.test.js b/tests/unit/ai-services-unified.test.js index 36da3756..10d094de 100644 --- a/tests/unit/ai-services-unified.test.js +++ b/tests/unit/ai-services-unified.test.js @@ -43,6 +43,7 @@ const mockGetBaseUrlForRole = jest.fn(); const mockGetAllProviders = jest.fn(); const mockGetOllamaBaseURL = jest.fn(); const mockGetAzureBaseURL = jest.fn(); +const mockGetBedrockBaseURL = jest.fn(); const mockGetVertexProjectId = jest.fn(); const mockGetVertexLocation = jest.fn(); const mockGetAvailableModels = jest.fn(); @@ -113,6 +114,7 @@ jest.unstable_mockModule('../../scripts/modules/config-manager.js', () => ({ getAllProviders: mockGetAllProviders, getOllamaBaseURL: mockGetOllamaBaseURL, getAzureBaseURL: mockGetAzureBaseURL, + getBedrockBaseURL: mockGetBedrockBaseURL, getVertexProjectId: mockGetVertexProjectId, getVertexLocation: mockGetVertexLocation, getMcpApiKeyStatus: mockGetMcpApiKeyStatus diff --git a/tests/unit/config-manager.test.js b/tests/unit/config-manager.test.js index 313ed32b..95686903 100644 --- a/tests/unit/config-manager.test.js +++ b/tests/unit/config-manager.test.js @@ -139,7 +139,8 @@ const DEFAULT_CONFIG = { defaultSubtasks: 5, defaultPriority: 'medium', projectName: 'Task Master', - ollamaBaseURL: 'http://localhost:11434/api' + ollamaBaseURL: 'http://localhost:11434/api', + bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com' } }; diff --git a/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js b/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js index 8902e61c..a555a488 100644 --- a/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js +++ b/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js @@ -127,6 +127,7 @@ jest.unstable_mockModule( getProjectName: jest.fn(() => 'Test Project'), getOllamaBaseURL: jest.fn(() => 'http://localhost:11434/api'), getAzureBaseURL: jest.fn(() => undefined), + getBedrockBaseURL: jest.fn(() => undefined), getParametersForRole: jest.fn(() => ({ maxTokens: 4000, temperature: 0.7