feat: add cursor_rules and self_improve support, enhance versioning

This commit is contained in:
Eyal Toledano
2025-03-21 14:06:36 -04:00
parent 9c564aa2e7
commit da61e9dccf
8 changed files with 900 additions and 321 deletions

View 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

View 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.

View File

@@ -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"
]
}
}

View File

@@ -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);

View File

@@ -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'));

View File

@@ -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');
}

File diff suppressed because it is too large Load Diff

View File

@@ -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