feat: add cursor_rules and self_improve support, enhance versioning
This commit is contained in:
53
.cursor/rules/cursor_rules.mdc
Normal file
53
.cursor/rules/cursor_rules.mdc
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
description: Guidelines for creating and maintaining Cursor rules to ensure consistency and effectiveness.
|
||||
globs: .cursor/rules/*.mdc
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
- **Required Rule Structure:**
|
||||
```markdown
|
||||
---
|
||||
description: Clear, one-line description of what the rule enforces
|
||||
globs: path/to/files/*.ext, other/path/**/*
|
||||
alwaysApply: boolean
|
||||
---
|
||||
|
||||
- **Main Points in Bold**
|
||||
- Sub-points with details
|
||||
- Examples and explanations
|
||||
```
|
||||
|
||||
- **File References:**
|
||||
- Use `[filename](mdc:path/to/file)` ([filename](mdc:filename)) to reference files
|
||||
- Example: [prisma.mdc](mdc:.cursor/rules/prisma.mdc) for rule references
|
||||
- Example: [schema.prisma](mdc:prisma/schema.prisma) for code references
|
||||
|
||||
- **Code Examples:**
|
||||
- Use language-specific code blocks
|
||||
```typescript
|
||||
// ✅ DO: Show good examples
|
||||
const goodExample = true;
|
||||
|
||||
// ❌ DON'T: Show anti-patterns
|
||||
const badExample = false;
|
||||
```
|
||||
|
||||
- **Rule Content Guidelines:**
|
||||
- Start with high-level overview
|
||||
- Include specific, actionable requirements
|
||||
- Show examples of correct implementation
|
||||
- Reference existing code when possible
|
||||
- Keep rules DRY by referencing other rules
|
||||
|
||||
- **Rule Maintenance:**
|
||||
- Update rules when new patterns emerge
|
||||
- Add examples from actual codebase
|
||||
- Remove outdated patterns
|
||||
- Cross-reference related rules
|
||||
|
||||
- **Best Practices:**
|
||||
- Use bullet points for clarity
|
||||
- Keep descriptions concise
|
||||
- Include both DO and DON'T examples
|
||||
- Reference actual code over theoretical examples
|
||||
- Use consistent formatting across rules
|
||||
73
.cursor/rules/self_improve.mdc
Normal file
73
.cursor/rules/self_improve.mdc
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
description: Guidelines for continuously improving Cursor rules based on emerging code patterns and best practices.
|
||||
globs: **/*
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
- **Rule Improvement Triggers:**
|
||||
- New code patterns not covered by existing rules
|
||||
- Repeated similar implementations across files
|
||||
- Common error patterns that could be prevented
|
||||
- New libraries or tools being used consistently
|
||||
- Emerging best practices in the codebase
|
||||
|
||||
- **Analysis Process:**
|
||||
- Compare new code with existing rules
|
||||
- Identify patterns that should be standardized
|
||||
- Look for references to external documentation
|
||||
- Check for consistent error handling patterns
|
||||
- Monitor test patterns and coverage
|
||||
|
||||
- **Rule Updates:**
|
||||
- **Add New Rules When:**
|
||||
- A new technology/pattern is used in 3+ files
|
||||
- Common bugs could be prevented by a rule
|
||||
- Code reviews repeatedly mention the same feedback
|
||||
- New security or performance patterns emerge
|
||||
|
||||
- **Modify Existing Rules When:**
|
||||
- Better examples exist in the codebase
|
||||
- Additional edge cases are discovered
|
||||
- Related rules have been updated
|
||||
- Implementation details have changed
|
||||
|
||||
- **Example Pattern Recognition:**
|
||||
```typescript
|
||||
// If you see repeated patterns like:
|
||||
const data = await prisma.user.findMany({
|
||||
select: { id: true, email: true },
|
||||
where: { status: 'ACTIVE' }
|
||||
});
|
||||
|
||||
// Consider adding to [prisma.mdc](mdc:.cursor/rules/prisma.mdc):
|
||||
// - Standard select fields
|
||||
// - Common where conditions
|
||||
// - Performance optimization patterns
|
||||
```
|
||||
|
||||
- **Rule Quality Checks:**
|
||||
- Rules should be actionable and specific
|
||||
- Examples should come from actual code
|
||||
- References should be up to date
|
||||
- Patterns should be consistently enforced
|
||||
|
||||
- **Continuous Improvement:**
|
||||
- Monitor code review comments
|
||||
- Track common development questions
|
||||
- Update rules after major refactors
|
||||
- Add links to relevant documentation
|
||||
- Cross-reference related rules
|
||||
|
||||
- **Rule Deprecation:**
|
||||
- Mark outdated patterns as deprecated
|
||||
- Remove rules that no longer apply
|
||||
- Update references to deprecated rules
|
||||
- Document migration paths for old patterns
|
||||
|
||||
- **Documentation Updates:**
|
||||
- Keep examples synchronized with code
|
||||
- Update references to external docs
|
||||
- Maintain links between related rules
|
||||
- Document breaking changes
|
||||
|
||||
Follow [cursor_rules.mdc](mdc:.cursor/rules/cursor_rules.mdc) for proper rule formatting and structure.
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claude-task-master",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"description": "A task management system for AI-driven development with Claude",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@@ -50,4 +50,4 @@
|
||||
"README.md",
|
||||
"index.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
122
scripts/dev.js
122
scripts/dev.js
@@ -537,7 +537,8 @@ function generateTaskFiles(tasksPath, outputDir) {
|
||||
const filename = `task_${String(task.id).padStart(3, '0')}.txt`;
|
||||
const filepath = path.join(outputDir, filename);
|
||||
|
||||
const content = [
|
||||
// Create the base content
|
||||
const contentParts = [
|
||||
`# Task ID: ${task.id}`,
|
||||
`# Title: ${task.title}`,
|
||||
`# Status: ${task.status}`,
|
||||
@@ -547,8 +548,24 @@ function generateTaskFiles(tasksPath, outputDir) {
|
||||
`# Details:\n${task.details}\n`,
|
||||
`# Test Strategy:`,
|
||||
`${task.testStrategy}\n`
|
||||
].join('\n');
|
||||
];
|
||||
|
||||
// Add subtasks if they exist
|
||||
if (task.subtasks && task.subtasks.length > 0) {
|
||||
contentParts.push(`# Subtasks:`);
|
||||
task.subtasks.forEach(subtask => {
|
||||
contentParts.push(`## Subtask ID: ${subtask.id}`);
|
||||
contentParts.push(`## Title: ${subtask.title}`);
|
||||
contentParts.push(`## Status: ${subtask.status}`);
|
||||
contentParts.push(`## Dependencies: ${subtask.dependencies ? subtask.dependencies.join(", ") : ""}`);
|
||||
contentParts.push(`## Description: ${subtask.description}`);
|
||||
if (subtask.acceptanceCriteria) {
|
||||
contentParts.push(`## Acceptance Criteria:\n${subtask.acceptanceCriteria}\n`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const content = contentParts.join('\n');
|
||||
fs.writeFileSync(filepath, content, 'utf8');
|
||||
log('info', `Generated: ${filename}`);
|
||||
});
|
||||
@@ -560,74 +577,94 @@ function generateTaskFiles(tasksPath, outputDir) {
|
||||
// 4) set-status
|
||||
//
|
||||
function setTaskStatus(tasksPath, taskIdInput, newStatus) {
|
||||
// For recursive calls with multiple IDs, we need to read the latest data each time
|
||||
// Validate inputs
|
||||
if (!taskIdInput || !newStatus) {
|
||||
log('error', 'Task ID and new status are required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Read fresh data for each status update
|
||||
const data = readJSON(tasksPath);
|
||||
if (!data || !data.tasks) {
|
||||
log('error', "No valid tasks found.");
|
||||
log('error', 'No valid tasks found in tasks.json');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Handle multiple task IDs (comma-separated)
|
||||
if (typeof taskIdInput === 'string' && taskIdInput.includes(',')) {
|
||||
const taskIds = taskIdInput.split(',').map(id => id.trim());
|
||||
log('info', `Processing multiple tasks: ${taskIds.join(', ')}`);
|
||||
log('info', `Processing multiple task IDs: ${taskIds.join(', ')}`);
|
||||
|
||||
// Process each task ID individually
|
||||
for (const taskId of taskIds) {
|
||||
// Create a new instance for each task to ensure we're working with fresh data
|
||||
setTaskStatus(tasksPath, taskId, newStatus);
|
||||
}
|
||||
|
||||
taskIds.forEach(id => {
|
||||
setTaskStatus(tasksPath, id, newStatus);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert numeric taskId to number if it's not a subtask ID
|
||||
const taskId = (!isNaN(taskIdInput) && !String(taskIdInput).includes('.'))
|
||||
? parseInt(taskIdInput, 10)
|
||||
: taskIdInput;
|
||||
|
||||
// Check if this is a subtask ID (e.g., "1.1")
|
||||
if (typeof taskId === 'string' && taskId.includes('.')) {
|
||||
const [parentIdStr, subtaskIdStr] = taskId.split('.');
|
||||
// Handle subtask IDs (e.g., "1.1")
|
||||
if (String(taskIdInput).includes('.')) {
|
||||
const [parentIdStr, subtaskIdStr] = String(taskIdInput).split('.');
|
||||
const parentId = parseInt(parentIdStr, 10);
|
||||
const subtaskId = parseInt(subtaskIdStr, 10);
|
||||
|
||||
|
||||
if (isNaN(parentId) || isNaN(subtaskId)) {
|
||||
log('error', `Invalid subtask ID format: ${taskIdInput}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Find the parent task
|
||||
const parentTask = data.tasks.find(t => t.id === parentId);
|
||||
|
||||
if (!parentTask) {
|
||||
log('error', `Parent task with ID=${parentId} not found.`);
|
||||
log('error', `Parent task ${parentId} not found`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!parentTask.subtasks || parentTask.subtasks.length === 0) {
|
||||
log('error', `Parent task with ID=${parentId} has no subtasks.`);
|
||||
|
||||
// Ensure subtasks array exists
|
||||
if (!parentTask.subtasks || !Array.isArray(parentTask.subtasks)) {
|
||||
log('error', `Parent task ${parentId} has no subtasks array`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
// Find and update the subtask
|
||||
const subtask = parentTask.subtasks.find(st => st.id === subtaskId);
|
||||
if (!subtask) {
|
||||
log('error', `Subtask with ID=${subtaskId} not found in parent task ID=${parentId}.`);
|
||||
log('error', `Subtask ${subtaskId} not found in task ${parentId}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const oldStatus = subtask.status;
|
||||
|
||||
// Update the subtask status
|
||||
const oldStatus = subtask.status || 'pending';
|
||||
subtask.status = newStatus;
|
||||
|
||||
// Save the changes
|
||||
writeJSON(tasksPath, data);
|
||||
log('info', `Subtask ${parentId}.${subtaskId} status changed from '${oldStatus}' to '${newStatus}'.`);
|
||||
log('info', `Updated subtask ${parentId}.${subtaskId} status from '${oldStatus}' to '${newStatus}'`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle regular task ID
|
||||
const task = data.tasks.find(t => t.id === taskId);
|
||||
if (!task) {
|
||||
log('error', `Task with ID=${taskId} not found.`);
|
||||
const taskId = parseInt(String(taskIdInput), 10);
|
||||
if (isNaN(taskId)) {
|
||||
log('error', `Invalid task ID: ${taskIdInput}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const oldStatus = task.status;
|
||||
// Find the task
|
||||
const task = data.tasks.find(t => t.id === taskId);
|
||||
if (!task) {
|
||||
log('error', `Task ${taskId} not found`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Update the task status
|
||||
const oldStatus = task.status || 'pending';
|
||||
task.status = newStatus;
|
||||
|
||||
// Save the changes
|
||||
writeJSON(tasksPath, data);
|
||||
log('info', `Task ID=${taskId} status changed from '${oldStatus}' to '${newStatus}'.`);
|
||||
log('info', `Updated task ${taskId} status from '${oldStatus}' to '${newStatus}'`);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1279,14 +1316,20 @@ async function main() {
|
||||
program
|
||||
.command('set-status')
|
||||
.description('Set the status of a task')
|
||||
.argument('<id>', 'Task ID')
|
||||
.argument('<status>', 'New status (todo, in-progress, review, done)')
|
||||
.option('-i, --id <id>', 'Task ID (can be comma-separated for multiple tasks)')
|
||||
.option('-s, --status <status>', 'New status (todo, in-progress, review, done)')
|
||||
.option('-f, --file <file>', 'Path to the tasks file', 'tasks/tasks.json')
|
||||
.action(async (id, status, options) => {
|
||||
.action(async (options) => {
|
||||
const tasksPath = options.file;
|
||||
const taskId = parseInt(id, 10);
|
||||
const taskId = options.id;
|
||||
const status = options.status;
|
||||
|
||||
console.log(chalk.blue(`Setting status of task ${taskId} to: ${status}`));
|
||||
if (!taskId || !status) {
|
||||
console.error(chalk.red('Error: Both --id and --status are required'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(chalk.blue(`Setting status of task(s) ${taskId} to: ${status}`));
|
||||
|
||||
await setTaskStatus(tasksPath, taskId, status);
|
||||
});
|
||||
@@ -1362,7 +1405,6 @@ async function main() {
|
||||
await program.parseAsync(process.argv);
|
||||
}
|
||||
|
||||
// ... existing code ...
|
||||
|
||||
main().catch(err => {
|
||||
log('error', err);
|
||||
|
||||
@@ -86,6 +86,12 @@ function copyTemplateFile(templateName, targetPath, replacements = {}) {
|
||||
case 'dev_workflow.mdc':
|
||||
sourcePath = path.join(__dirname, '..', '.cursor', 'rules', 'dev_workflow.mdc');
|
||||
break;
|
||||
case 'cursor_rules.mdc':
|
||||
sourcePath = path.join(__dirname, '..', '.cursor', 'rules', 'cursor_rules.mdc');
|
||||
break;
|
||||
case 'self_improve.mdc':
|
||||
sourcePath = path.join(__dirname, '..', '.cursor', 'rules', 'self_improve.mdc');
|
||||
break;
|
||||
case 'README.md':
|
||||
sourcePath = path.join(__dirname, '..', 'README.md');
|
||||
break;
|
||||
@@ -234,6 +240,12 @@ function createProjectStructure(projectName, projectDescription, projectVersion,
|
||||
// Copy dev_workflow.mdc
|
||||
copyTemplateFile('dev_workflow.mdc', path.join(targetDir, '.cursor', 'rules', 'dev_workflow.mdc'));
|
||||
|
||||
// Copy cursor_rules.mdc
|
||||
copyTemplateFile('cursor_rules.mdc', path.join(targetDir, '.cursor', 'rules', 'cursor_rules.mdc'));
|
||||
|
||||
// Copy self_improve.mdc
|
||||
copyTemplateFile('self_improve.mdc', path.join(targetDir, '.cursor', 'rules', 'self_improve.mdc'));
|
||||
|
||||
// Copy scripts/dev.js
|
||||
copyTemplateFile('dev.js', path.join(targetDir, 'scripts', 'dev.js'));
|
||||
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
/**
|
||||
* This script prepares the package for publication to NPM.
|
||||
* It ensures all necessary files are included and properly configured.
|
||||
*
|
||||
* Additional options:
|
||||
* --patch: Increment patch version (default)
|
||||
* --minor: Increment minor version
|
||||
* --major: Increment major version
|
||||
* --version=x.y.z: Set specific version
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
@@ -27,6 +33,16 @@ const COLORS = {
|
||||
cyan: '\x1b[36m'
|
||||
};
|
||||
|
||||
// Parse command line arguments
|
||||
const args = process.argv.slice(2);
|
||||
const versionBump = args.includes('--major') ? 'major' :
|
||||
args.includes('--minor') ? 'minor' :
|
||||
'patch';
|
||||
|
||||
// Check for explicit version
|
||||
const versionArg = args.find(arg => arg.startsWith('--version='));
|
||||
const explicitVersion = versionArg ? versionArg.split('=')[1] : null;
|
||||
|
||||
// Log function with color support
|
||||
function log(level, ...args) {
|
||||
const prefix = {
|
||||
@@ -63,11 +79,44 @@ function syncTemplateFiles() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to increment version
|
||||
function incrementVersion(currentVersion, type = 'patch') {
|
||||
const [major, minor, patch] = currentVersion.split('.').map(Number);
|
||||
|
||||
switch (type) {
|
||||
case 'major':
|
||||
return `${major + 1}.0.0`;
|
||||
case 'minor':
|
||||
return `${major}.${minor + 1}.0`;
|
||||
case 'patch':
|
||||
default:
|
||||
return `${major}.${minor}.${patch + 1}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Main function to prepare the package
|
||||
function preparePackage() {
|
||||
const rootDir = path.join(__dirname, '..');
|
||||
log('info', `Preparing package in ${rootDir}`);
|
||||
|
||||
// Update version in package.json
|
||||
const packageJsonPath = path.join(rootDir, 'package.json');
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||
const currentVersion = packageJson.version;
|
||||
|
||||
let newVersion;
|
||||
if (explicitVersion) {
|
||||
newVersion = explicitVersion;
|
||||
log('info', `Setting version to specified ${newVersion} (was ${currentVersion})`);
|
||||
} else {
|
||||
newVersion = incrementVersion(currentVersion, versionBump);
|
||||
log('info', `Incrementing ${versionBump} version to ${newVersion} (was ${currentVersion})`);
|
||||
}
|
||||
|
||||
packageJson.version = newVersion;
|
||||
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
||||
log('success', `Updated package.json version to ${newVersion}`);
|
||||
|
||||
// Check for required files
|
||||
const requiredFiles = [
|
||||
'package.json',
|
||||
@@ -78,7 +127,9 @@ function preparePackage() {
|
||||
'assets/env.example',
|
||||
'assets/gitignore',
|
||||
'assets/example_prd.txt',
|
||||
'.cursor/rules/dev_workflow.mdc'
|
||||
'.cursor/rules/dev_workflow.mdc',
|
||||
'.cursor/rules/cursor_rules.mdc',
|
||||
'.cursor/rules/self_improve.mdc'
|
||||
];
|
||||
|
||||
let allFilesExist = true;
|
||||
@@ -134,7 +185,8 @@ function preparePackage() {
|
||||
log('error', 'Failed to make scripts executable:', error.message);
|
||||
}
|
||||
|
||||
log('success', 'Package preparation completed successfully!');
|
||||
log('success', `Package preparation completed successfully! 🎉`);
|
||||
log('success', `Version updated to ${newVersion}`);
|
||||
log('info', 'You can now publish the package with:');
|
||||
log('info', ' npm publish');
|
||||
}
|
||||
|
||||
898
templates/dev.js
898
templates/dev.js
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
# Required
|
||||
ANTHROPIC_API_KEY=your-api-key-here # Format: sk-ant-api03-...
|
||||
PERPLEXITY_API_KEY=pplx-abcde
|
||||
|
||||
# Optional - defaults shown
|
||||
MODEL=claude-3-7-sonnet-20250219 # Recommended models: claude-3-7-sonnet-20250219, claude-3-opus-20240229
|
||||
@@ -10,4 +11,4 @@ LOG_LEVEL=info # Log level (debug, info, warn, error)
|
||||
DEFAULT_SUBTASKS=3 # Default number of subtasks when expanding
|
||||
DEFAULT_PRIORITY=medium # Default priority for generated tasks (high, medium, low)
|
||||
PROJECT_NAME={{projectName}} # Project name for tasks.json metadata
|
||||
PROJECT_VERSION={{projectVersion}} # Project version for tasks.json metadata
|
||||
PROJECT_VERSION={{projectVersion}} # Project version for tasks.json metadata
|
||||
Reference in New Issue
Block a user