Compare commits

..

3 Commits

Author SHA1 Message Date
Ralph Khreish
4a169dec1f fix: change to MIT License 2025-03-31 09:36:47 +02:00
Ralph Khreish
aaca4253a6 chore: add license to project 2025-03-30 21:41:23 +02:00
Ralph Khreish
197f6b0c53 Add MIT License 2025-03-30 21:04:54 +02:00
15 changed files with 48 additions and 189 deletions

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": patch
---
Added changeset config #39

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": minor
---
add github actions to automate github and npm releases

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": minor
---
Implement MCP server for all commands using tools.

View File

@@ -1,5 +0,0 @@
---
"task-master-ai": patch
---
Fix github actions creating npm releases on next branch push

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": patch
---
Fix addTask tool `projectRoot not defined`

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": patch
---
Add license to repo

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": patch
---
fix mcp server not connecting to cursor

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": patch
---
Fix workflows

View File

@@ -3,6 +3,7 @@ on:
push:
branches:
- main
- next
jobs:
release:
runs-on: ubuntu-latest

View File

@@ -1,27 +0,0 @@
# task-master-ai
## 0.10.1
### Patch Changes
- [#80](https://github.com/eyaltoledano/claude-task-master/pull/80) [`aa185b2`](https://github.com/eyaltoledano/claude-task-master/commit/aa185b28b248b4ca93f9195b502e2f5187868eaa) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Remove non-existent package `@model-context-protocol/sdk`
- [#45](https://github.com/eyaltoledano/claude-task-master/pull/45) [`757fd47`](https://github.com/eyaltoledano/claude-task-master/commit/757fd478d2e2eff8506ae746c3470c6088f4d944) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add license to repo
## 0.10.0
### Minor Changes
- [#44](https://github.com/eyaltoledano/claude-task-master/pull/44) [`eafdb47`](https://github.com/eyaltoledano/claude-task-master/commit/eafdb47418b444c03c092f653b438cc762d4bca8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - add github actions to automate github and npm releases
- [#20](https://github.com/eyaltoledano/claude-task-master/pull/20) [`4eed269`](https://github.com/eyaltoledano/claude-task-master/commit/4eed2693789a444f704051d5fbb3ef8d460e4e69) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Implement MCP server for all commands using tools.
### Patch Changes
- [#44](https://github.com/eyaltoledano/claude-task-master/pull/44) [`44db895`](https://github.com/eyaltoledano/claude-task-master/commit/44db895303a9209416236e3d519c8a609ad85f61) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added changeset config #39
- [#50](https://github.com/eyaltoledano/claude-task-master/pull/50) [`257160a`](https://github.com/eyaltoledano/claude-task-master/commit/257160a9670b5d1942e7c623bd2c1a3fde7c06a0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix addTask tool `projectRoot not defined`
- [#57](https://github.com/eyaltoledano/claude-task-master/pull/57) [`9fd42ee`](https://github.com/eyaltoledano/claude-task-master/commit/9fd42eeafdc25a96cdfb70aa3af01f525d26b4bc) Thanks [@github-actions](https://github.com/apps/github-actions)! - fix mcp server not connecting to cursor
- [#48](https://github.com/eyaltoledano/claude-task-master/pull/48) [`5ec3651`](https://github.com/eyaltoledano/claude-task-master/commit/5ec3651e6459add7354910a86b3c4db4d12bc5d1) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix workflows

2
package-lock.json generated
View File

@@ -7,7 +7,7 @@
"": {
"name": "task-master-ai",
"version": "0.9.30",
"license": "(BSL-1.1 AND Apache-2.0)",
"license": "MIT",
"dependencies": {
"@anthropic-ai/sdk": "^0.39.0",
"boxen": "^8.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "task-master-ai",
"version": "0.10.1",
"version": "0.9.30",
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
"main": "index.js",
"type": "module",
@@ -37,6 +37,7 @@
"license": "MIT WITH Commons-Clause",
"dependencies": {
"@anthropic-ai/sdk": "^0.39.0",
"@model-context-protocol/sdk": "^1.20.5",
"boxen": "^8.0.1",
"chalk": "^4.1.2",
"cli-table3": "^0.6.5",

View File

@@ -41,8 +41,7 @@ import {
displayNextTask,
displayTaskById,
displayComplexityReport,
getStatusWithColor,
confirmTaskOverwrite
getStatusWithColor
} from './ui.js';
/**
@@ -71,34 +70,17 @@ function registerCommands(programInstance) {
.option('-i, --input <file>', 'Path to the PRD file (alternative to positional argument)')
.option('-o, --output <file>', 'Output file path', 'tasks/tasks.json')
.option('-n, --num-tasks <number>', 'Number of tasks to generate', '10')
.option('-f, --force', 'Skip confirmation when overwriting existing tasks')
.action(async (file, options) => {
// Use input option if file argument not provided
const inputFile = file || options.input;
const defaultPrdPath = 'scripts/prd.txt';
const numTasks = parseInt(options.numTasks, 10);
const outputPath = options.output;
const force = options.force || false;
// Helper function to check if tasks.json exists and confirm overwrite
async function confirmOverwriteIfNeeded() {
if (fs.existsSync(outputPath) && !force) {
const shouldContinue = await confirmTaskOverwrite(outputPath);
if (!shouldContinue) {
console.log(chalk.yellow('Operation cancelled by user.'));
return false;
}
}
return true;
}
// If no input file specified, check for default PRD location
if (!inputFile) {
if (fs.existsSync(defaultPrdPath)) {
console.log(chalk.blue(`Using default PRD file: ${defaultPrdPath}`));
// Check for existing tasks.json before proceeding
if (!await confirmOverwriteIfNeeded()) return;
const numTasks = parseInt(options.numTasks, 10);
const outputPath = options.output;
console.log(chalk.blue(`Generating ${numTasks} tasks...`));
await parsePRD(defaultPrdPath, outputPath, numTasks);
@@ -113,12 +95,10 @@ function registerCommands(programInstance) {
chalk.cyan('Options:') + '\n' +
' -i, --input <file> Path to the PRD file (alternative to positional argument)\n' +
' -o, --output <file> Output file path (default: "tasks/tasks.json")\n' +
' -n, --num-tasks <number> Number of tasks to generate (default: 10)\n' +
' -f, --force Skip confirmation when overwriting existing tasks\n\n' +
' -n, --num-tasks <number> Number of tasks to generate (default: 10)\n\n' +
chalk.cyan('Example:') + '\n' +
' task-master parse-prd requirements.txt --num-tasks 15\n' +
' task-master parse-prd --input=requirements.txt\n' +
' task-master parse-prd --force\n\n' +
' task-master parse-prd --input=requirements.txt\n\n' +
chalk.yellow('Note: This command will:') + '\n' +
' 1. Look for a PRD file at scripts/prd.txt by default\n' +
' 2. Use the file specified by --input or positional argument if provided\n' +
@@ -128,8 +108,8 @@ function registerCommands(programInstance) {
return;
}
// Check for existing tasks.json before proceeding with specified input file
if (!await confirmOverwriteIfNeeded()) return;
const numTasks = parseInt(options.numTasks, 10);
const outputPath = options.output;
console.log(chalk.blue(`Parsing PRD file: ${inputFile}`));
console.log(chalk.blue(`Generating ${numTasks} tasks...`));

View File

@@ -1061,33 +1061,6 @@ async function displayComplexityReport(reportPath) {
));
}
/**
* Confirm overwriting existing tasks.json file
* @param {string} tasksPath - Path to the tasks.json file
* @returns {Promise<boolean>} - Promise resolving to true if user confirms, false otherwise
*/
async function confirmTaskOverwrite(tasksPath) {
console.log(boxen(
chalk.yellow('It looks like you\'ve already generated tasks for this project.\n') +
chalk.yellow('Executing this command will overwrite any existing tasks.'),
{ padding: 1, borderColor: 'yellow', borderStyle: 'round', margin: { top: 1 } }
));
// Use dynamic import to get the readline module
const readline = await import('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const answer = await new Promise(resolve => {
rl.question(chalk.cyan('Are you sure you wish to continue? (y/N): '), resolve);
});
rl.close();
return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
}
// Export UI functions
export {
displayBanner,
@@ -1101,5 +1074,4 @@ export {
displayNextTask,
displayTaskById,
displayComplexityReport,
confirmTaskOverwrite
};

View File

@@ -25,7 +25,6 @@ const mockIsTaskDependentOn = jest.fn().mockReturnValue(false);
const mockCreate = jest.fn(); // Mock for Anthropic messages.create
const mockChatCompletionsCreate = jest.fn(); // Mock for Perplexity chat.completions.create
const mockGetAvailableAIModel = jest.fn(); // <<<<< Added mock function
const mockPromptYesNo = jest.fn(); // Mock for confirmation prompt
// Mock fs module
jest.mock('fs', () => ({
@@ -77,7 +76,6 @@ jest.mock('../../scripts/modules/utils.js', () => ({
readComplexityReport: jest.fn(), // <<<<< Added mock
findTaskInComplexityReport: jest.fn(), // <<<<< Added mock
truncate: jest.fn((str, len) => str.slice(0, len)), // <<<<< Added mock
promptYesNo: mockPromptYesNo, // Added mock for confirmation prompt
}));
// Mock AI services - Update this mock
@@ -131,19 +129,6 @@ jest.mock('../../scripts/modules/task-manager.js', () => {
// Create a simplified version of parsePRD for testing
const testParsePRD = async (prdPath, outputPath, numTasks) => {
try {
// Check if the output file already exists
if (mockExistsSync(outputPath)) {
const confirmOverwrite = await mockPromptYesNo(
`Warning: ${outputPath} already exists. Overwrite?`,
false
);
if (!confirmOverwrite) {
console.log(`Operation cancelled. ${outputPath} was not modified.`);
return null;
}
}
const prdContent = mockReadFileSync(prdPath, 'utf8');
const tasks = await mockCallClaude(prdContent, prdPath, numTasks);
const dir = mockDirname(outputPath);
@@ -578,7 +563,6 @@ describe('Task Manager Module', () => {
mockDirname.mockReturnValue('tasks');
mockCallClaude.mockResolvedValue(sampleClaudeResponse);
mockGenerateTaskFiles.mockResolvedValue(undefined);
mockPromptYesNo.mockResolvedValue(true); // Default to "yes" for confirmation
});
test('should parse a PRD file and generate tasks', async () => {
@@ -602,13 +586,8 @@ describe('Task Manager Module', () => {
});
test('should create the tasks directory if it does not exist', async () => {
// Mock existsSync to return false specifically for the directory check
// but true for the output file check (so we don't trigger confirmation path)
mockExistsSync.mockImplementation((path) => {
if (path === 'tasks/tasks.json') return false; // Output file doesn't exist
if (path === 'tasks') return false; // Directory doesn't exist
return true; // Default for other paths
});
// Mock existsSync to return false to simulate directory doesn't exist
mockExistsSync.mockReturnValueOnce(false);
// Call the function
await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
@@ -645,83 +624,6 @@ describe('Task Manager Module', () => {
// Verify generateTaskFiles was called
expect(mockGenerateTaskFiles).toHaveBeenCalledWith('tasks/tasks.json', 'tasks');
});
test('should prompt for confirmation when tasks.json already exists', async () => {
// Setup mocks to simulate tasks.json already exists
mockExistsSync.mockImplementation((path) => {
if (path === 'tasks/tasks.json') return true; // Output file exists
if (path === 'tasks') return true; // Directory exists
return false;
});
// Call the function
await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
// Verify prompt was called with expected message
expect(mockPromptYesNo).toHaveBeenCalledWith(
'Warning: tasks/tasks.json already exists. Overwrite?',
false
);
// Verify the file was written after confirmation
expect(mockWriteJSON).toHaveBeenCalledWith('tasks/tasks.json', sampleClaudeResponse);
});
test('should not overwrite tasks.json when user declines confirmation', async () => {
// Setup mocks to simulate tasks.json already exists
mockExistsSync.mockImplementation((path) => {
if (path === 'tasks/tasks.json') return true; // Output file exists
if (path === 'tasks') return true; // Directory exists
return false;
});
// Mock user declining the confirmation
mockPromptYesNo.mockResolvedValueOnce(false);
// Mock console.log to capture output
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
// Call the function
const result = await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
// Verify prompt was called
expect(mockPromptYesNo).toHaveBeenCalledWith(
'Warning: tasks/tasks.json already exists. Overwrite?',
false
);
// Verify the file was NOT written
expect(mockWriteJSON).not.toHaveBeenCalled();
// Verify appropriate message was logged
expect(mockConsoleLog).toHaveBeenCalledWith(
'Operation cancelled. tasks/tasks.json was not modified.'
);
// Verify result is null when operation is cancelled
expect(result).toBeNull();
// Restore console.log
mockConsoleLog.mockRestore();
});
test('should not prompt for confirmation when tasks.json does not exist', async () => {
// Setup mocks to simulate tasks.json does not exist
mockExistsSync.mockImplementation((path) => {
if (path === 'tasks/tasks.json') return false; // Output file doesn't exist
if (path === 'tasks') return true; // Directory exists
return false;
});
// Call the function
await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
// Verify prompt was NOT called
expect(mockPromptYesNo).not.toHaveBeenCalled();
// Verify the file was written without confirmation
expect(mockWriteJSON).toHaveBeenCalledWith('tasks/tasks.json', sampleClaudeResponse);
});
});
describe.skip('updateTasks function', () => {