diff --git a/.changeset/spicy-badgers-fail.md b/.changeset/spicy-badgers-fail.md new file mode 100644 index 00000000..665378e9 --- /dev/null +++ b/.changeset/spicy-badgers-fail.md @@ -0,0 +1,5 @@ +--- +"task-master-ai": patch +--- + +Unify and streamline profile system architecture for improved maintainability diff --git a/assets/claude/TM_COMMANDS_GUIDE.md b/assets/claude/TM_COMMANDS_GUIDE.md new file mode 100644 index 00000000..c88bcb1c --- /dev/null +++ b/assets/claude/TM_COMMANDS_GUIDE.md @@ -0,0 +1,147 @@ +# Task Master Commands for Claude Code + +Complete guide to using Task Master through Claude Code's slash commands. + +## Overview + +All Task Master functionality is available through the `/project:tm/` namespace with natural language support and intelligent features. + +## Quick Start + +```bash +# Install Task Master +/project:tm/setup/quick-install + +# Initialize project +/project:tm/init/quick + +# Parse requirements +/project:tm/parse-prd requirements.md + +# Start working +/project:tm/next +``` + +## Command Structure + +Commands are organized hierarchically to match Task Master's CLI: +- Main commands at `/project:tm/[command]` +- Subcommands for specific operations `/project:tm/[command]/[subcommand]` +- Natural language arguments accepted throughout + +## Complete Command Reference + +### Setup & Configuration +- `/project:tm/setup/install` - Full installation guide +- `/project:tm/setup/quick-install` - One-line install +- `/project:tm/init` - Initialize project +- `/project:tm/init/quick` - Quick init with -y +- `/project:tm/models` - View AI config +- `/project:tm/models/setup` - Configure AI + +### Task Generation +- `/project:tm/parse-prd` - Generate from PRD +- `/project:tm/parse-prd/with-research` - Enhanced parsing +- `/project:tm/generate` - Create task files + +### Task Management +- `/project:tm/list` - List with natural language filters +- `/project:tm/list/with-subtasks` - Hierarchical view +- `/project:tm/list/by-status ` - Filter by status +- `/project:tm/show ` - Task details +- `/project:tm/add-task` - Create task +- `/project:tm/update` - Update tasks +- `/project:tm/remove-task` - Delete task + +### Status Management +- `/project:tm/set-status/to-pending ` +- `/project:tm/set-status/to-in-progress ` +- `/project:tm/set-status/to-done ` +- `/project:tm/set-status/to-review ` +- `/project:tm/set-status/to-deferred ` +- `/project:tm/set-status/to-cancelled ` + +### Task Analysis +- `/project:tm/analyze-complexity` - AI analysis +- `/project:tm/complexity-report` - View report +- `/project:tm/expand ` - Break down task +- `/project:tm/expand/all` - Expand all complex + +### Dependencies +- `/project:tm/add-dependency` - Add dependency +- `/project:tm/remove-dependency` - Remove dependency +- `/project:tm/validate-dependencies` - Check issues +- `/project:tm/fix-dependencies` - Auto-fix + +### Workflows +- `/project:tm/workflows/smart-flow` - Adaptive workflows +- `/project:tm/workflows/pipeline` - Chain commands +- `/project:tm/workflows/auto-implement` - AI implementation + +### Utilities +- `/project:tm/status` - Project dashboard +- `/project:tm/next` - Next task recommendation +- `/project:tm/utils/analyze` - Project analysis +- `/project:tm/learn` - Interactive help + +## Key Features + +### Natural Language Support +All commands understand natural language: +``` +/project:tm/list pending high priority +/project:tm/update mark 23 as done +/project:tm/add-task implement OAuth login +``` + +### Smart Context +Commands analyze project state and provide intelligent suggestions based on: +- Current task status +- Dependencies +- Team patterns +- Project phase + +### Visual Enhancements +- Progress bars and indicators +- Status badges +- Organized displays +- Clear hierarchies + +## Common Workflows + +### Daily Development +``` +/project:tm/workflows/smart-flow morning +/project:tm/next +/project:tm/set-status/to-in-progress +/project:tm/set-status/to-done +``` + +### Task Breakdown +``` +/project:tm/show +/project:tm/expand +/project:tm/list/with-subtasks +``` + +### Sprint Planning +``` +/project:tm/analyze-complexity +/project:tm/workflows/pipeline init → expand/all → status +``` + +## Migration from Old Commands + +| Old | New | +|-----|-----| +| `/project:task-master:list` | `/project:tm/list` | +| `/project:task-master:complete` | `/project:tm/set-status/to-done` | +| `/project:workflows:auto-implement` | `/project:tm/workflows/auto-implement` | + +## Tips + +1. Use `/project:tm/` + Tab for command discovery +2. Natural language is supported everywhere +3. Commands provide smart defaults +4. Chain commands for automation +5. Check `/project:tm/learn` for interactive help \ No newline at end of file diff --git a/assets/claude/commands/tm/add-dependency/add-dependency.md b/assets/claude/commands/tm/add-dependency/add-dependency.md new file mode 100644 index 00000000..78e91546 --- /dev/null +++ b/assets/claude/commands/tm/add-dependency/add-dependency.md @@ -0,0 +1,55 @@ +Add a dependency between tasks. + +Arguments: $ARGUMENTS + +Parse the task IDs to establish dependency relationship. + +## Adding Dependencies + +Creates a dependency where one task must be completed before another can start. + +## Argument Parsing + +Parse natural language or IDs: +- "make 5 depend on 3" → task 5 depends on task 3 +- "5 needs 3" → task 5 depends on task 3 +- "5 3" → task 5 depends on task 3 +- "5 after 3" → task 5 depends on task 3 + +## Execution + +```bash +task-master add-dependency --id= --depends-on= +``` + +## Validation + +Before adding: +1. **Verify both tasks exist** +2. **Check for circular dependencies** +3. **Ensure dependency makes logical sense** +4. **Warn if creating complex chains** + +## Smart Features + +- Detect if dependency already exists +- Suggest related dependencies +- Show impact on task flow +- Update task priorities if needed + +## Post-Addition + +After adding dependency: +1. Show updated dependency graph +2. Identify any newly blocked tasks +3. Suggest task order changes +4. Update project timeline + +## Example Flows + +``` +/project:tm/add-dependency 5 needs 3 +→ Task #5 now depends on Task #3 +→ Task #5 is now blocked until #3 completes +→ Suggested: Also consider if #5 needs #4 +``` \ No newline at end of file diff --git a/assets/claude/commands/tm/add-subtask/add-subtask.md b/assets/claude/commands/tm/add-subtask/add-subtask.md new file mode 100644 index 00000000..d909dd5d --- /dev/null +++ b/assets/claude/commands/tm/add-subtask/add-subtask.md @@ -0,0 +1,76 @@ +Add a subtask to a parent task. + +Arguments: $ARGUMENTS + +Parse arguments to create a new subtask or convert existing task. + +## Adding Subtasks + +Creates subtasks to break down complex parent tasks into manageable pieces. + +## Argument Parsing + +Flexible natural language: +- "add subtask to 5: implement login form" +- "break down 5 with: setup, implement, test" +- "subtask for 5: handle edge cases" +- "5: validate user input" → adds subtask to task 5 + +## Execution Modes + +### 1. Create New Subtask +```bash +task-master add-subtask --parent= --title="" --description="<desc>" +``` + +### 2. Convert Existing Task +```bash +task-master add-subtask --parent=<id> --task-id=<existing-id> +``` + +## Smart Features + +1. **Automatic Subtask Generation** + - If title contains "and" or commas, create multiple + - Suggest common subtask patterns + - Inherit parent's context + +2. **Intelligent Defaults** + - Priority based on parent + - Appropriate time estimates + - Logical dependencies between subtasks + +3. **Validation** + - Check parent task complexity + - Warn if too many subtasks + - Ensure subtask makes sense + +## Creation Process + +1. Parse parent task context +2. Generate subtask with ID like "5.1" +3. Set appropriate defaults +4. Link to parent task +5. Update parent's time estimate + +## Example Flows + +``` +/project:tm/add-subtask to 5: implement user authentication +→ Created subtask #5.1: "implement user authentication" +→ Parent task #5 now has 1 subtask +→ Suggested next subtasks: tests, documentation + +/project:tm/add-subtask 5: setup, implement, test +→ Created 3 subtasks: + #5.1: setup + #5.2: implement + #5.3: test +``` + +## Post-Creation + +- Show updated task hierarchy +- Suggest logical next subtasks +- Update complexity estimates +- Recommend subtask order \ No newline at end of file diff --git a/assets/claude/commands/tm/add-subtask/convert-task-to-subtask.md b/assets/claude/commands/tm/add-subtask/convert-task-to-subtask.md new file mode 100644 index 00000000..ab20730f --- /dev/null +++ b/assets/claude/commands/tm/add-subtask/convert-task-to-subtask.md @@ -0,0 +1,71 @@ +Convert an existing task into a subtask. + +Arguments: $ARGUMENTS + +Parse parent ID and task ID to convert. + +## Task Conversion + +Converts an existing standalone task into a subtask of another task. + +## Argument Parsing + +- "move task 8 under 5" +- "make 8 a subtask of 5" +- "nest 8 in 5" +- "5 8" → make task 8 a subtask of task 5 + +## Execution + +```bash +task-master add-subtask --parent=<parent-id> --task-id=<task-to-convert> +``` + +## Pre-Conversion Checks + +1. **Validation** + - Both tasks exist and are valid + - No circular parent relationships + - Task isn't already a subtask + - Logical hierarchy makes sense + +2. **Impact Analysis** + - Dependencies that will be affected + - Tasks that depend on converting task + - Priority alignment needed + - Status compatibility + +## Conversion Process + +1. Change task ID from "8" to "5.1" (next available) +2. Update all dependency references +3. Inherit parent's context where appropriate +4. Adjust priorities if needed +5. Update time estimates + +## Smart Features + +- Preserve task history +- Maintain dependencies +- Update all references +- Create conversion log + +## Example + +``` +/project:tm/add-subtask/from-task 5 8 +→ Converting: Task #8 becomes subtask #5.1 +→ Updated: 3 dependency references +→ Parent task #5 now has 1 subtask +→ Note: Subtask inherits parent's priority + +Before: #8 "Implement validation" (standalone) +After: #5.1 "Implement validation" (subtask of #5) +``` + +## Post-Conversion + +- Show new task hierarchy +- List updated dependencies +- Verify project integrity +- Suggest related conversions \ No newline at end of file diff --git a/assets/claude/commands/tm/add-task/add-task.md b/assets/claude/commands/tm/add-task/add-task.md new file mode 100644 index 00000000..0c1c09c3 --- /dev/null +++ b/assets/claude/commands/tm/add-task/add-task.md @@ -0,0 +1,78 @@ +Add new tasks with intelligent parsing and context awareness. + +Arguments: $ARGUMENTS + +## Smart Task Addition + +Parse natural language to create well-structured tasks. + +### 1. **Input Understanding** + +I'll intelligently parse your request: +- Natural language → Structured task +- Detect priority from keywords (urgent, ASAP, important) +- Infer dependencies from context +- Suggest complexity based on description +- Determine task type (feature, bug, refactor, test, docs) + +### 2. **Smart Parsing Examples** + +**"Add urgent task to fix login bug"** +→ Title: Fix login bug +→ Priority: high +→ Type: bug +→ Suggested complexity: medium + +**"Create task for API documentation after task 23 is done"** +→ Title: API documentation +→ Dependencies: [23] +→ Type: documentation +→ Priority: medium + +**"Need to refactor auth module - depends on 12 and 15, high complexity"** +→ Title: Refactor auth module +→ Dependencies: [12, 15] +→ Complexity: high +→ Type: refactor + +### 3. **Context Enhancement** + +Based on current project state: +- Suggest related existing tasks +- Warn about potential conflicts +- Recommend dependencies +- Propose subtasks if complex + +### 4. **Interactive Refinement** + +```yaml +Task Preview: +───────────── +Title: [Extracted title] +Priority: [Inferred priority] +Dependencies: [Detected dependencies] +Complexity: [Estimated complexity] + +Suggestions: +- Similar task #34 exists, consider as dependency? +- This seems complex, break into subtasks? +- Tasks #45-47 work on same module +``` + +### 5. **Validation & Creation** + +Before creating: +- Validate dependencies exist +- Check for duplicates +- Ensure logical ordering +- Verify task completeness + +### 6. **Smart Defaults** + +Intelligent defaults based on: +- Task type patterns +- Team conventions +- Historical data +- Current sprint/phase + +Result: High-quality tasks from minimal input. \ No newline at end of file diff --git a/assets/claude/commands/tm/analyze-complexity/analyze-complexity.md b/assets/claude/commands/tm/analyze-complexity/analyze-complexity.md new file mode 100644 index 00000000..807f4b12 --- /dev/null +++ b/assets/claude/commands/tm/analyze-complexity/analyze-complexity.md @@ -0,0 +1,121 @@ +Analyze task complexity and generate expansion recommendations. + +Arguments: $ARGUMENTS + +Perform deep analysis of task complexity across the project. + +## Complexity Analysis + +Uses AI to analyze tasks and recommend which ones need breakdown. + +## Execution Options + +```bash +task-master analyze-complexity [--research] [--threshold=5] +``` + +## Analysis Parameters + +- `--research` → Use research AI for deeper analysis +- `--threshold=5` → Only flag tasks above complexity 5 +- Default: Analyze all pending tasks + +## Analysis Process + +### 1. **Task Evaluation** +For each task, AI evaluates: +- Technical complexity +- Time requirements +- Dependency complexity +- Risk factors +- Knowledge requirements + +### 2. **Complexity Scoring** +Assigns score 1-10 based on: +- Implementation difficulty +- Integration challenges +- Testing requirements +- Unknown factors +- Technical debt risk + +### 3. **Recommendations** +For complex tasks: +- Suggest expansion approach +- Recommend subtask breakdown +- Identify risk areas +- Propose mitigation strategies + +## Smart Analysis Features + +1. **Pattern Recognition** + - Similar task comparisons + - Historical complexity accuracy + - Team velocity consideration + - Technology stack factors + +2. **Contextual Factors** + - Team expertise + - Available resources + - Timeline constraints + - Business criticality + +3. **Risk Assessment** + - Technical risks + - Timeline risks + - Dependency risks + - Knowledge gaps + +## Output Format + +``` +Task Complexity Analysis Report +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +High Complexity Tasks (>7): +📍 #5 "Implement real-time sync" - Score: 9/10 + Factors: WebSocket complexity, state management, conflict resolution + Recommendation: Expand into 5-7 subtasks + Risks: Performance, data consistency + +📍 #12 "Migrate database schema" - Score: 8/10 + Factors: Data migration, zero downtime, rollback strategy + Recommendation: Expand into 4-5 subtasks + Risks: Data loss, downtime + +Medium Complexity Tasks (5-7): +📍 #23 "Add export functionality" - Score: 6/10 + Consider expansion if timeline tight + +Low Complexity Tasks (<5): +✅ 15 tasks - No expansion needed + +Summary: +- Expand immediately: 2 tasks +- Consider expanding: 5 tasks +- Keep as-is: 15 tasks +``` + +## Actionable Output + +For each high-complexity task: +1. Complexity score with reasoning +2. Specific expansion suggestions +3. Risk mitigation approaches +4. Recommended subtask structure + +## Integration + +Results are: +- Saved to `.taskmaster/reports/complexity-analysis.md` +- Used by expand command +- Inform sprint planning +- Guide resource allocation + +## Next Steps + +After analysis: +``` +/project:tm/expand 5 # Expand specific task +/project:tm/expand/all # Expand all recommended +/project:tm/complexity-report # View detailed report +``` \ No newline at end of file diff --git a/assets/claude/commands/tm/clear-subtasks/clear-all-subtasks.md b/assets/claude/commands/tm/clear-subtasks/clear-all-subtasks.md new file mode 100644 index 00000000..6cd54d7d --- /dev/null +++ b/assets/claude/commands/tm/clear-subtasks/clear-all-subtasks.md @@ -0,0 +1,93 @@ +Clear all subtasks from all tasks globally. + +## Global Subtask Clearing + +Remove all subtasks across the entire project. Use with extreme caution. + +## Execution + +```bash +task-master clear-subtasks --all +``` + +## Pre-Clear Analysis + +1. **Project-Wide Summary** + ``` + Global Subtask Summary + ━━━━━━━━━━━━━━━━━━━━ + Total parent tasks: 12 + Total subtasks: 47 + - Completed: 15 + - In-progress: 8 + - Pending: 24 + + Work at risk: ~120 hours + ``` + +2. **Critical Warnings** + - In-progress subtasks that will lose work + - Completed subtasks with valuable history + - Complex dependency chains + - Integration test results + +## Double Confirmation + +``` +⚠️ DESTRUCTIVE OPERATION WARNING ⚠️ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +This will remove ALL 47 subtasks from your project +Including 8 in-progress and 15 completed subtasks + +This action CANNOT be undone + +Type 'CLEAR ALL SUBTASKS' to confirm: +``` + +## Smart Safeguards + +- Require explicit confirmation phrase +- Create automatic backup +- Log all removed data +- Option to export first + +## Use Cases + +Valid reasons for global clear: +- Project restructuring +- Major pivot in approach +- Starting fresh breakdown +- Switching to different task organization + +## Process + +1. Full project analysis +2. Create backup file +3. Show detailed impact +4. Require confirmation +5. Execute removal +6. Generate summary report + +## Alternative Suggestions + +Before clearing all: +- Export subtasks to file +- Clear only pending subtasks +- Clear by task category +- Archive instead of delete + +## Post-Clear Report + +``` +Global Subtask Clear Complete +━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Removed: 47 subtasks from 12 tasks +Backup saved: .taskmaster/backup/subtasks-20240115.json +Parent tasks updated: 12 +Time estimates adjusted: Yes + +Next steps: +- Review updated task list +- Re-expand complex tasks as needed +- Check project timeline +``` \ No newline at end of file diff --git a/assets/claude/commands/tm/clear-subtasks/clear-subtasks.md b/assets/claude/commands/tm/clear-subtasks/clear-subtasks.md new file mode 100644 index 00000000..877ceb8c --- /dev/null +++ b/assets/claude/commands/tm/clear-subtasks/clear-subtasks.md @@ -0,0 +1,86 @@ +Clear all subtasks from a specific task. + +Arguments: $ARGUMENTS (task ID) + +Remove all subtasks from a parent task at once. + +## Clearing Subtasks + +Bulk removal of all subtasks from a parent task. + +## Execution + +```bash +task-master clear-subtasks --id=<task-id> +``` + +## Pre-Clear Analysis + +1. **Subtask Summary** + - Number of subtasks + - Completion status of each + - Work already done + - Dependencies affected + +2. **Impact Assessment** + - Data that will be lost + - Dependencies to be removed + - Effect on project timeline + - Parent task implications + +## Confirmation Required + +``` +Clear Subtasks Confirmation +━━━━━━━━━━━━━━━━━━━━━━━━━ +Parent Task: #5 "Implement user authentication" +Subtasks to remove: 4 +- #5.1 "Setup auth framework" (done) +- #5.2 "Create login form" (in-progress) +- #5.3 "Add validation" (pending) +- #5.4 "Write tests" (pending) + +⚠️ This will permanently delete all subtask data +Continue? (y/n) +``` + +## Smart Features + +- Option to convert to standalone tasks +- Backup task data before clearing +- Preserve completed work history +- Update parent task appropriately + +## Process + +1. List all subtasks for confirmation +2. Check for in-progress work +3. Remove all subtasks +4. Update parent task +5. Clean up dependencies + +## Alternative Options + +Suggest alternatives: +- Convert important subtasks to tasks +- Keep completed subtasks +- Archive instead of delete +- Export subtask data first + +## Post-Clear + +- Show updated parent task +- Recalculate time estimates +- Update task complexity +- Suggest next steps + +## Example + +``` +/project:tm/clear-subtasks 5 +→ Found 4 subtasks to remove +→ Warning: Subtask #5.2 is in-progress +→ Cleared all subtasks from task #5 +→ Updated parent task estimates +→ Suggestion: Consider re-expanding with better breakdown +``` \ No newline at end of file diff --git a/assets/claude/commands/tm/complexity-report/complexity-report.md b/assets/claude/commands/tm/complexity-report/complexity-report.md new file mode 100644 index 00000000..16d2d11d --- /dev/null +++ b/assets/claude/commands/tm/complexity-report/complexity-report.md @@ -0,0 +1,117 @@ +Display the task complexity analysis report. + +Arguments: $ARGUMENTS + +View the detailed complexity analysis generated by analyze-complexity command. + +## Viewing Complexity Report + +Shows comprehensive task complexity analysis with actionable insights. + +## Execution + +```bash +task-master complexity-report [--file=<path>] +``` + +## Report Location + +Default: `.taskmaster/reports/complexity-analysis.md` +Custom: Specify with --file parameter + +## Report Contents + +### 1. **Executive Summary** +``` +Complexity Analysis Summary +━━━━━━━━━━━━━━━━━━━━━━━━ +Analysis Date: 2024-01-15 +Tasks Analyzed: 32 +High Complexity: 5 (16%) +Medium Complexity: 12 (37%) +Low Complexity: 15 (47%) + +Critical Findings: +- 5 tasks need immediate expansion +- 3 tasks have high technical risk +- 2 tasks block critical path +``` + +### 2. **Detailed Task Analysis** +For each complex task: +- Complexity score breakdown +- Contributing factors +- Specific risks identified +- Expansion recommendations +- Similar completed tasks + +### 3. **Risk Matrix** +Visual representation: +``` +Risk vs Complexity Matrix +━━━━━━━━━━━━━━━━━━━━━━━ +High Risk | #5(9) #12(8) | #23(6) +Med Risk | #34(7) | #45(5) #67(5) +Low Risk | #78(8) | [15 tasks] + | High Complex | Med Complex +``` + +### 4. **Recommendations** + +**Immediate Actions:** +1. Expand task #5 - Critical path + high complexity +2. Expand task #12 - High risk + dependencies +3. Review task #34 - Consider splitting + +**Sprint Planning:** +- Don't schedule multiple high-complexity tasks together +- Ensure expertise available for complex tasks +- Build in buffer time for unknowns + +## Interactive Features + +When viewing report: +1. **Quick Actions** + - Press 'e' to expand a task + - Press 'd' for task details + - Press 'r' to refresh analysis + +2. **Filtering** + - View by complexity level + - Filter by risk factors + - Show only actionable items + +3. **Export Options** + - Markdown format + - CSV for spreadsheets + - JSON for tools + +## Report Intelligence + +- Compares with historical data +- Shows complexity trends +- Identifies patterns +- Suggests process improvements + +## Integration + +Use report for: +- Sprint planning sessions +- Resource allocation +- Risk assessment +- Team discussions +- Client updates + +## Example Usage + +``` +/project:tm/complexity-report +→ Opens latest analysis + +/project:tm/complexity-report --file=archived/2024-01-01.md +→ View historical analysis + +After viewing: +/project:tm/expand 5 +→ Expand high-complexity task +``` \ No newline at end of file diff --git a/assets/claude/commands/tm/expand/expand-all-tasks.md b/assets/claude/commands/tm/expand/expand-all-tasks.md new file mode 100644 index 00000000..ec87789d --- /dev/null +++ b/assets/claude/commands/tm/expand/expand-all-tasks.md @@ -0,0 +1,51 @@ +Expand all pending tasks that need subtasks. + +## Bulk Task Expansion + +Intelligently expands all tasks that would benefit from breakdown. + +## Execution + +```bash +task-master expand --all +``` + +## Smart Selection + +Only expands tasks that: +- Are marked as pending +- Have high complexity (>5) +- Lack existing subtasks +- Would benefit from breakdown + +## Expansion Process + +1. **Analysis Phase** + - Identify expansion candidates + - Group related tasks + - Plan expansion strategy + +2. **Batch Processing** + - Expand tasks in logical order + - Maintain consistency + - Preserve relationships + - Optimize for parallelism + +3. **Quality Control** + - Ensure subtask quality + - Avoid over-decomposition + - Maintain task coherence + - Update dependencies + +## Options + +- Add `force` to expand all regardless of complexity +- Add `research` for enhanced AI analysis + +## Results + +After bulk expansion: +- Summary of tasks expanded +- New subtask count +- Updated complexity metrics +- Suggested task order \ No newline at end of file diff --git a/assets/claude/commands/tm/expand/expand-task.md b/assets/claude/commands/tm/expand/expand-task.md new file mode 100644 index 00000000..78555b98 --- /dev/null +++ b/assets/claude/commands/tm/expand/expand-task.md @@ -0,0 +1,49 @@ +Break down a complex task into subtasks. + +Arguments: $ARGUMENTS (task ID) + +## Intelligent Task Expansion + +Analyzes a task and creates detailed subtasks for better manageability. + +## Execution + +```bash +task-master expand --id=$ARGUMENTS +``` + +## Expansion Process + +1. **Task Analysis** + - Review task complexity + - Identify components + - Detect technical challenges + - Estimate time requirements + +2. **Subtask Generation** + - Create 3-7 subtasks typically + - Each subtask 1-4 hours + - Logical implementation order + - Clear acceptance criteria + +3. **Smart Breakdown** + - Setup/configuration tasks + - Core implementation + - Testing components + - Integration steps + - Documentation updates + +## Enhanced Features + +Based on task type: +- **Feature**: Setup → Implement → Test → Integrate +- **Bug Fix**: Reproduce → Diagnose → Fix → Verify +- **Refactor**: Analyze → Plan → Refactor → Validate + +## Post-Expansion + +After expansion: +1. Show subtask hierarchy +2. Update time estimates +3. Suggest implementation order +4. Highlight critical path \ No newline at end of file diff --git a/assets/claude/commands/tm/fix-dependencies/fix-dependencies.md b/assets/claude/commands/tm/fix-dependencies/fix-dependencies.md new file mode 100644 index 00000000..9fa857ca --- /dev/null +++ b/assets/claude/commands/tm/fix-dependencies/fix-dependencies.md @@ -0,0 +1,81 @@ +Automatically fix dependency issues found during validation. + +## Automatic Dependency Repair + +Intelligently fixes common dependency problems while preserving project logic. + +## Execution + +```bash +task-master fix-dependencies +``` + +## What Gets Fixed + +### 1. **Auto-Fixable Issues** +- Remove references to deleted tasks +- Break simple circular dependencies +- Remove self-dependencies +- Clean up duplicate dependencies + +### 2. **Smart Resolutions** +- Reorder dependencies to maintain logic +- Suggest task merging for over-dependent tasks +- Flatten unnecessary dependency chains +- Remove redundant transitive dependencies + +### 3. **Manual Review Required** +- Complex circular dependencies +- Critical path modifications +- Business logic dependencies +- High-impact changes + +## Fix Process + +1. **Analysis Phase** + - Run validation check + - Categorize issues by type + - Determine fix strategy + +2. **Execution Phase** + - Apply automatic fixes + - Log all changes made + - Preserve task relationships + +3. **Verification Phase** + - Re-validate after fixes + - Show before/after comparison + - Highlight manual fixes needed + +## Smart Features + +- Preserves intended task flow +- Minimal disruption approach +- Creates fix history/log +- Suggests manual interventions + +## Output Example + +``` +Dependency Auto-Fix Report +━━━━━━━━━━━━━━━━━━━━━━━━ +Fixed Automatically: +✅ Removed 2 references to deleted tasks +✅ Resolved 1 self-dependency +✅ Cleaned 3 redundant dependencies + +Manual Review Needed: +⚠️ Complex circular dependency: #12 → #15 → #18 → #12 + Suggestion: Make #15 not depend on #12 +⚠️ Task #45 has 8 dependencies + Suggestion: Break into subtasks + +Run '/project:tm/validate-dependencies' to verify fixes +``` + +## Safety + +- Preview mode available +- Rollback capability +- Change logging +- No data loss \ No newline at end of file diff --git a/assets/claude/commands/tm/generate/generate-tasks.md b/assets/claude/commands/tm/generate/generate-tasks.md new file mode 100644 index 00000000..01140d75 --- /dev/null +++ b/assets/claude/commands/tm/generate/generate-tasks.md @@ -0,0 +1,121 @@ +Generate individual task files from tasks.json. + +## Task File Generation + +Creates separate markdown files for each task, perfect for AI agents or documentation. + +## Execution + +```bash +task-master generate +``` + +## What It Creates + +For each task, generates a file like `task_001.txt`: + +``` +Task ID: 1 +Title: Implement user authentication +Status: pending +Priority: high +Dependencies: [] +Created: 2024-01-15 +Complexity: 7 + +## Description +Create a secure user authentication system with login, logout, and session management. + +## Details +- Use JWT tokens for session management +- Implement secure password hashing +- Add remember me functionality +- Include password reset flow + +## Test Strategy +- Unit tests for auth functions +- Integration tests for login flow +- Security testing for vulnerabilities +- Performance tests for concurrent logins + +## Subtasks +1.1 Setup authentication framework (pending) +1.2 Create login endpoints (pending) +1.3 Implement session management (pending) +1.4 Add password reset (pending) +``` + +## File Organization + +Creates structure: +``` +.taskmaster/ +└── tasks/ + ├── task_001.txt + ├── task_002.txt + ├── task_003.txt + └── ... +``` + +## Smart Features + +1. **Consistent Formatting** + - Standardized structure + - Clear sections + - AI-readable format + - Markdown compatible + +2. **Contextual Information** + - Full task details + - Related task references + - Progress indicators + - Implementation notes + +3. **Incremental Updates** + - Only regenerate changed tasks + - Preserve custom additions + - Track generation timestamp + - Version control friendly + +## Use Cases + +- **AI Context**: Provide task context to AI assistants +- **Documentation**: Standalone task documentation +- **Archival**: Task history preservation +- **Sharing**: Send specific tasks to team members +- **Review**: Easier task review process + +## Generation Options + +Based on arguments: +- Filter by status +- Include/exclude completed +- Custom templates +- Different formats + +## Post-Generation + +``` +Task File Generation Complete +━━━━━━━━━━━━━━━━━━━━━━━━━━ +Generated: 45 task files +Location: .taskmaster/tasks/ +Total size: 156 KB + +New files: 5 +Updated files: 12 +Unchanged: 28 + +Ready for: +- AI agent consumption +- Version control +- Team distribution +``` + +## Integration Benefits + +- Git-trackable task history +- Easy task sharing +- AI tool compatibility +- Offline task access +- Backup redundancy \ No newline at end of file diff --git a/assets/claude/commands/tm/help.md b/assets/claude/commands/tm/help.md new file mode 100644 index 00000000..d68df206 --- /dev/null +++ b/assets/claude/commands/tm/help.md @@ -0,0 +1,81 @@ +Show help for Task Master commands. + +Arguments: $ARGUMENTS + +Display help for Task Master commands. If arguments provided, show specific command help. + +## Task Master Command Help + +### Quick Navigation + +Type `/project:tm/` and use tab completion to explore all commands. + +### Command Categories + +#### 🚀 Setup & Installation +- `/project:tm/setup/install` - Comprehensive installation guide +- `/project:tm/setup/quick-install` - One-line global install + +#### 📋 Project Setup +- `/project:tm/init` - Initialize new project +- `/project:tm/init/quick` - Quick setup with auto-confirm +- `/project:tm/models` - View AI configuration +- `/project:tm/models/setup` - Configure AI providers + +#### 🎯 Task Generation +- `/project:tm/parse-prd` - Generate tasks from PRD +- `/project:tm/parse-prd/with-research` - Enhanced parsing +- `/project:tm/generate` - Create task files + +#### 📝 Task Management +- `/project:tm/list` - List tasks (natural language filters) +- `/project:tm/show <id>` - Display task details +- `/project:tm/add-task` - Create new task +- `/project:tm/update` - Update tasks naturally +- `/project:tm/next` - Get next task recommendation + +#### 🔄 Status Management +- `/project:tm/set-status/to-pending <id>` +- `/project:tm/set-status/to-in-progress <id>` +- `/project:tm/set-status/to-done <id>` +- `/project:tm/set-status/to-review <id>` +- `/project:tm/set-status/to-deferred <id>` +- `/project:tm/set-status/to-cancelled <id>` + +#### 🔍 Analysis & Breakdown +- `/project:tm/analyze-complexity` - Analyze task complexity +- `/project:tm/expand <id>` - Break down complex task +- `/project:tm/expand/all` - Expand all eligible tasks + +#### 🔗 Dependencies +- `/project:tm/add-dependency` - Add task dependency +- `/project:tm/remove-dependency` - Remove dependency +- `/project:tm/validate-dependencies` - Check for issues + +#### 🤖 Workflows +- `/project:tm/workflows/smart-flow` - Intelligent workflows +- `/project:tm/workflows/pipeline` - Command chaining +- `/project:tm/workflows/auto-implement` - Auto-implementation + +#### 📊 Utilities +- `/project:tm/utils/analyze` - Project analysis +- `/project:tm/status` - Project dashboard +- `/project:tm/learn` - Interactive learning + +### Natural Language Examples + +``` +/project:tm/list pending high priority +/project:tm/update mark all API tasks as done +/project:tm/add-task create login system with OAuth +/project:tm/show current +``` + +### Getting Started + +1. Install: `/project:tm/setup/quick-install` +2. Initialize: `/project:tm/init/quick` +3. Learn: `/project:tm/learn start` +4. Work: `/project:tm/workflows/smart-flow` + +For detailed command info: `/project:tm/help <command-name>` \ No newline at end of file diff --git a/assets/claude/commands/tm/init/init-project-quick.md b/assets/claude/commands/tm/init/init-project-quick.md new file mode 100644 index 00000000..1fb8eb67 --- /dev/null +++ b/assets/claude/commands/tm/init/init-project-quick.md @@ -0,0 +1,46 @@ +Quick initialization with auto-confirmation. + +Arguments: $ARGUMENTS + +Initialize a Task Master project without prompts, accepting all defaults. + +## Quick Setup + +```bash +task-master init -y +``` + +## What It Does + +1. Creates `.taskmaster/` directory structure +2. Initializes empty `tasks.json` +3. Sets up default configuration +4. Uses directory name as project name +5. Skips all confirmation prompts + +## Smart Defaults + +- Project name: Current directory name +- Description: "Task Master Project" +- Model config: Existing environment vars +- Task structure: Standard format + +## Next Steps + +After quick init: +1. Configure AI models if needed: + ``` + /project:tm/models/setup + ``` + +2. Parse PRD if available: + ``` + /project:tm/parse-prd <file> + ``` + +3. Or create first task: + ``` + /project:tm/add-task create initial setup + ``` + +Perfect for rapid project setup! \ No newline at end of file diff --git a/assets/claude/commands/tm/init/init-project.md b/assets/claude/commands/tm/init/init-project.md new file mode 100644 index 00000000..f2598dff --- /dev/null +++ b/assets/claude/commands/tm/init/init-project.md @@ -0,0 +1,50 @@ +Initialize a new Task Master project. + +Arguments: $ARGUMENTS + +Parse arguments to determine initialization preferences. + +## Initialization Process + +1. **Parse Arguments** + - PRD file path (if provided) + - Project name + - Auto-confirm flag (-y) + +2. **Project Setup** + ```bash + task-master init + ``` + +3. **Smart Initialization** + - Detect existing project files + - Suggest project name from directory + - Check for git repository + - Verify AI provider configuration + +## Configuration Options + +Based on arguments: +- `quick` / `-y` → Skip confirmations +- `<file.md>` → Use as PRD after init +- `--name=<name>` → Set project name +- `--description=<desc>` → Set description + +## Post-Initialization + +After successful init: +1. Show project structure created +2. Verify AI models configured +3. Suggest next steps: + - Parse PRD if available + - Configure AI providers + - Set up git hooks + - Create first tasks + +## Integration + +If PRD file provided: +``` +/project:tm/init my-prd.md +→ Automatically runs parse-prd after init +``` \ No newline at end of file diff --git a/assets/claude/commands/tm/learn.md b/assets/claude/commands/tm/learn.md new file mode 100644 index 00000000..0ffe5455 --- /dev/null +++ b/assets/claude/commands/tm/learn.md @@ -0,0 +1,103 @@ +Learn about Task Master capabilities through interactive exploration. + +Arguments: $ARGUMENTS + +## Interactive Task Master Learning + +Based on your input, I'll help you discover capabilities: + +### 1. **What are you trying to do?** + +If $ARGUMENTS contains: +- "start" / "begin" → Show project initialization workflows +- "manage" / "organize" → Show task management commands +- "automate" / "auto" → Show automation workflows +- "analyze" / "report" → Show analysis tools +- "fix" / "problem" → Show troubleshooting commands +- "fast" / "quick" → Show efficiency shortcuts + +### 2. **Intelligent Suggestions** + +Based on your project state: + +**No tasks yet?** +``` +You'll want to start with: +1. /project:task-master:init <prd-file> + → Creates tasks from requirements + +2. /project:task-master:parse-prd <file> + → Alternative task generation + +Try: /project:task-master:init demo-prd.md +``` + +**Have tasks?** +Let me analyze what you might need... +- Many pending tasks? → Learn sprint planning +- Complex tasks? → Learn task expansion +- Daily work? → Learn workflow automation + +### 3. **Command Discovery** + +**By Category:** +- 📋 Task Management: list, show, add, update, complete +- 🔄 Workflows: auto-implement, sprint-plan, daily-standup +- 🛠️ Utilities: check-health, complexity-report, sync-memory +- 🔍 Analysis: validate-deps, show dependencies + +**By Scenario:** +- "I want to see what to work on" → `/project:task-master:next` +- "I need to break this down" → `/project:task-master:expand <id>` +- "Show me everything" → `/project:task-master:status` +- "Just do it for me" → `/project:workflows:auto-implement` + +### 4. **Power User Patterns** + +**Command Chaining:** +``` +/project:task-master:next +/project:task-master:start <id> +/project:workflows:auto-implement +``` + +**Smart Filters:** +``` +/project:task-master:list pending high +/project:task-master:list blocked +/project:task-master:list 1-5 tree +``` + +**Automation:** +``` +/project:workflows:pipeline init → expand-all → sprint-plan +``` + +### 5. **Learning Path** + +Based on your experience level: + +**Beginner Path:** +1. init → Create project +2. status → Understand state +3. next → Find work +4. complete → Finish task + +**Intermediate Path:** +1. expand → Break down complex tasks +2. sprint-plan → Organize work +3. complexity-report → Understand difficulty +4. validate-deps → Ensure consistency + +**Advanced Path:** +1. pipeline → Chain operations +2. smart-flow → Context-aware automation +3. Custom commands → Extend the system + +### 6. **Try This Now** + +Based on what you asked about, try: +[Specific command suggestion based on $ARGUMENTS] + +Want to learn more about a specific command? +Type: /project:help <command-name> \ No newline at end of file diff --git a/assets/claude/commands/tm/list/list-tasks-by-status.md b/assets/claude/commands/tm/list/list-tasks-by-status.md new file mode 100644 index 00000000..e9524ffd --- /dev/null +++ b/assets/claude/commands/tm/list/list-tasks-by-status.md @@ -0,0 +1,39 @@ +List tasks filtered by a specific status. + +Arguments: $ARGUMENTS + +Parse the status from arguments and list only tasks matching that status. + +## Status Options +- `pending` - Not yet started +- `in-progress` - Currently being worked on +- `done` - Completed +- `review` - Awaiting review +- `deferred` - Postponed +- `cancelled` - Cancelled + +## Execution + +Based on $ARGUMENTS, run: +```bash +task-master list --status=$ARGUMENTS +``` + +## Enhanced Display + +For the filtered results: +- Group by priority within the status +- Show time in current status +- Highlight tasks approaching deadlines +- Display blockers and dependencies +- Suggest next actions for each status group + +## Intelligent Insights + +Based on the status filter: +- **Pending**: Show recommended start order +- **In-Progress**: Display idle time warnings +- **Done**: Show newly unblocked tasks +- **Review**: Indicate review duration +- **Deferred**: Show reactivation criteria +- **Cancelled**: Display impact analysis \ No newline at end of file diff --git a/assets/claude/commands/tm/list/list-tasks-with-subtasks.md b/assets/claude/commands/tm/list/list-tasks-with-subtasks.md new file mode 100644 index 00000000..407e0ba4 --- /dev/null +++ b/assets/claude/commands/tm/list/list-tasks-with-subtasks.md @@ -0,0 +1,29 @@ +List all tasks including their subtasks in a hierarchical view. + +This command shows all tasks with their nested subtasks, providing a complete project overview. + +## Execution + +Run the Task Master list command with subtasks flag: +```bash +task-master list --with-subtasks +``` + +## Enhanced Display + +I'll organize the output to show: +- Parent tasks with clear indicators +- Nested subtasks with proper indentation +- Status badges for quick scanning +- Dependencies and blockers highlighted +- Progress indicators for tasks with subtasks + +## Smart Filtering + +Based on the task hierarchy: +- Show completion percentage for parent tasks +- Highlight blocked subtask chains +- Group by functional areas +- Indicate critical path items + +This gives you a complete tree view of your project structure. \ No newline at end of file diff --git a/assets/claude/commands/tm/list/list-tasks.md b/assets/claude/commands/tm/list/list-tasks.md new file mode 100644 index 00000000..74374af5 --- /dev/null +++ b/assets/claude/commands/tm/list/list-tasks.md @@ -0,0 +1,43 @@ +List tasks with intelligent argument parsing. + +Parse arguments to determine filters and display options: +- Status: pending, in-progress, done, review, deferred, cancelled +- Priority: high, medium, low (or priority:high) +- Special: subtasks, tree, dependencies, blocked +- IDs: Direct numbers (e.g., "1,3,5" or "1-5") +- Complex: "pending high" = pending AND high priority + +Arguments: $ARGUMENTS + +Let me parse your request intelligently: + +1. **Detect Filter Intent** + - If arguments contain status keywords → filter by status + - If arguments contain priority → filter by priority + - If arguments contain "subtasks" → include subtasks + - If arguments contain "tree" → hierarchical view + - If arguments contain numbers → show specific tasks + - If arguments contain "blocked" → show blocked tasks only + +2. **Smart Combinations** + Examples of what I understand: + - "pending high" → pending tasks with high priority + - "done today" → tasks completed today + - "blocked" → tasks with unmet dependencies + - "1-5" → tasks 1 through 5 + - "subtasks tree" → hierarchical view with subtasks + +3. **Execute Appropriate Query** + Based on parsed intent, run the most specific task-master command + +4. **Enhanced Display** + - Group by relevant criteria + - Show most important information first + - Use visual indicators for quick scanning + - Include relevant metrics + +5. **Intelligent Suggestions** + Based on what you're viewing, suggest next actions: + - Many pending? → Suggest priority order + - Many blocked? → Show dependency resolution + - Looking at specific tasks? → Show related tasks \ No newline at end of file diff --git a/assets/claude/commands/tm/models/setup-models.md b/assets/claude/commands/tm/models/setup-models.md new file mode 100644 index 00000000..367a7c8d --- /dev/null +++ b/assets/claude/commands/tm/models/setup-models.md @@ -0,0 +1,51 @@ +Run interactive setup to configure AI models. + +## Interactive Model Configuration + +Guides you through setting up AI providers for Task Master. + +## Execution + +```bash +task-master models --setup +``` + +## Setup Process + +1. **Environment Check** + - Detect existing API keys + - Show current configuration + - Identify missing providers + +2. **Provider Selection** + - Choose main provider (required) + - Select research provider (recommended) + - Configure fallback (optional) + +3. **API Key Configuration** + - Prompt for missing keys + - Validate key format + - Test connectivity + - Save configuration + +## Smart Recommendations + +Based on your needs: +- **For best results**: Claude + Perplexity +- **Budget conscious**: GPT-3.5 + Perplexity +- **Maximum capability**: GPT-4 + Perplexity + Claude fallback + +## Configuration Storage + +Keys can be stored in: +1. Environment variables (recommended) +2. `.env` file in project +3. Global `.taskmaster/config` + +## Post-Setup + +After configuration: +- Test each provider +- Show usage examples +- Suggest next steps +- Verify parse-prd works \ No newline at end of file diff --git a/assets/claude/commands/tm/models/view-models.md b/assets/claude/commands/tm/models/view-models.md new file mode 100644 index 00000000..61ac989a --- /dev/null +++ b/assets/claude/commands/tm/models/view-models.md @@ -0,0 +1,51 @@ +View current AI model configuration. + +## Model Configuration Display + +Shows the currently configured AI providers and models for Task Master. + +## Execution + +```bash +task-master models +``` + +## Information Displayed + +1. **Main Provider** + - Model ID and name + - API key status (configured/missing) + - Usage: Primary task generation + +2. **Research Provider** + - Model ID and name + - API key status + - Usage: Enhanced research mode + +3. **Fallback Provider** + - Model ID and name + - API key status + - Usage: Backup when main fails + +## Visual Status + +``` +Task Master AI Model Configuration +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Main: ✅ claude-3-5-sonnet (configured) +Research: ✅ perplexity-sonar (configured) +Fallback: ⚠️ Not configured (optional) + +Available Models: +- claude-3-5-sonnet +- gpt-4-turbo +- gpt-3.5-turbo +- perplexity-sonar +``` + +## Next Actions + +Based on configuration: +- If missing API keys → Suggest setup +- If no research model → Explain benefits +- If all configured → Show usage tips \ No newline at end of file diff --git a/assets/claude/commands/tm/next/next-task.md b/assets/claude/commands/tm/next/next-task.md new file mode 100644 index 00000000..1af74d94 --- /dev/null +++ b/assets/claude/commands/tm/next/next-task.md @@ -0,0 +1,66 @@ +Intelligently determine and prepare the next action based on comprehensive context. + +This enhanced version of 'next' considers: +- Current task states +- Recent activity +- Time constraints +- Dependencies +- Your working patterns + +Arguments: $ARGUMENTS + +## Intelligent Next Action + +### 1. **Context Gathering** +Let me analyze the current situation: +- Active tasks (in-progress) +- Recently completed tasks +- Blocked tasks +- Time since last activity +- Arguments provided: $ARGUMENTS + +### 2. **Smart Decision Tree** + +**If you have an in-progress task:** +- Has it been idle > 2 hours? → Suggest resuming or switching +- Near completion? → Show remaining steps +- Blocked? → Find alternative task + +**If no in-progress tasks:** +- Unblocked high-priority tasks? → Start highest +- Complex tasks need breakdown? → Suggest expansion +- All tasks blocked? → Show dependency resolution + +**Special arguments handling:** +- "quick" → Find task < 2 hours +- "easy" → Find low complexity task +- "important" → Find high priority regardless of complexity +- "continue" → Resume last worked task + +### 3. **Preparation Workflow** + +Based on selected task: +1. Show full context and history +2. Set up development environment +3. Run relevant tests +4. Open related files +5. Show similar completed tasks +6. Estimate completion time + +### 4. **Alternative Suggestions** + +Always provide options: +- Primary recommendation +- Quick alternative (< 1 hour) +- Strategic option (unblocks most tasks) +- Learning option (new technology/skill) + +### 5. **Workflow Integration** + +Seamlessly connect to: +- `/project:task-master:start [selected]` +- `/project:workflows:auto-implement` +- `/project:task-master:expand` (if complex) +- `/project:utils:complexity-report` (if unsure) + +The goal: Zero friction from decision to implementation. \ No newline at end of file diff --git a/assets/claude/commands/tm/parse-prd/parse-prd-with-research.md b/assets/claude/commands/tm/parse-prd/parse-prd-with-research.md new file mode 100644 index 00000000..8be39e83 --- /dev/null +++ b/assets/claude/commands/tm/parse-prd/parse-prd-with-research.md @@ -0,0 +1,48 @@ +Parse PRD with enhanced research mode for better task generation. + +Arguments: $ARGUMENTS (PRD file path) + +## Research-Enhanced Parsing + +Uses the research AI provider (typically Perplexity) for more comprehensive task generation with current best practices. + +## Execution + +```bash +task-master parse-prd --input=$ARGUMENTS --research +``` + +## Research Benefits + +1. **Current Best Practices** + - Latest framework patterns + - Security considerations + - Performance optimizations + - Accessibility requirements + +2. **Technical Deep Dive** + - Implementation approaches + - Library recommendations + - Architecture patterns + - Testing strategies + +3. **Comprehensive Coverage** + - Edge cases consideration + - Error handling tasks + - Monitoring setup + - Deployment tasks + +## Enhanced Output + +Research mode typically: +- Generates more detailed tasks +- Includes industry standards +- Adds compliance considerations +- Suggests modern tooling + +## When to Use + +- New technology domains +- Complex requirements +- Regulatory compliance needed +- Best practices crucial \ No newline at end of file diff --git a/assets/claude/commands/tm/parse-prd/parse-prd.md b/assets/claude/commands/tm/parse-prd/parse-prd.md new file mode 100644 index 00000000..f299c714 --- /dev/null +++ b/assets/claude/commands/tm/parse-prd/parse-prd.md @@ -0,0 +1,49 @@ +Parse a PRD document to generate tasks. + +Arguments: $ARGUMENTS (PRD file path) + +## Intelligent PRD Parsing + +Analyzes your requirements document and generates a complete task breakdown. + +## Execution + +```bash +task-master parse-prd --input=$ARGUMENTS +``` + +## Parsing Process + +1. **Document Analysis** + - Extract key requirements + - Identify technical components + - Detect dependencies + - Estimate complexity + +2. **Task Generation** + - Create 10-15 tasks by default + - Include implementation tasks + - Add testing tasks + - Include documentation tasks + - Set logical dependencies + +3. **Smart Enhancements** + - Group related functionality + - Set appropriate priorities + - Add acceptance criteria + - Include test strategies + +## Options + +Parse arguments for modifiers: +- Number after filename → `--num-tasks` +- `research` → Use research mode +- `comprehensive` → Generate more tasks + +## Post-Generation + +After parsing: +1. Display task summary +2. Show dependency graph +3. Suggest task expansion for complex items +4. Recommend sprint planning \ No newline at end of file diff --git a/assets/claude/commands/tm/remove-dependency/remove-dependency.md b/assets/claude/commands/tm/remove-dependency/remove-dependency.md new file mode 100644 index 00000000..9f5936e6 --- /dev/null +++ b/assets/claude/commands/tm/remove-dependency/remove-dependency.md @@ -0,0 +1,62 @@ +Remove a dependency between tasks. + +Arguments: $ARGUMENTS + +Parse the task IDs to remove dependency relationship. + +## Removing Dependencies + +Removes a dependency relationship, potentially unblocking tasks. + +## Argument Parsing + +Parse natural language or IDs: +- "remove dependency between 5 and 3" +- "5 no longer needs 3" +- "unblock 5 from 3" +- "5 3" → remove dependency of 5 on 3 + +## Execution + +```bash +task-master remove-dependency --id=<task-id> --depends-on=<dependency-id> +``` + +## Pre-Removal Checks + +1. **Verify dependency exists** +2. **Check impact on task flow** +3. **Warn if it breaks logical sequence** +4. **Show what will be unblocked** + +## Smart Analysis + +Before removing: +- Show why dependency might have existed +- Check if removal makes tasks executable +- Verify no critical path disruption +- Suggest alternative dependencies + +## Post-Removal + +After removing: +1. Show updated task status +2. List newly unblocked tasks +3. Update project timeline +4. Suggest next actions + +## Safety Features + +- Confirm if removing critical dependency +- Show tasks that become immediately actionable +- Warn about potential issues +- Keep removal history + +## Example + +``` +/project:tm/remove-dependency 5 from 3 +→ Removed: Task #5 no longer depends on #3 +→ Task #5 is now UNBLOCKED and ready to start +→ Warning: Consider if #5 still needs #2 completed first +``` \ No newline at end of file diff --git a/assets/claude/commands/tm/remove-subtask/remove-subtask.md b/assets/claude/commands/tm/remove-subtask/remove-subtask.md new file mode 100644 index 00000000..e5a814f8 --- /dev/null +++ b/assets/claude/commands/tm/remove-subtask/remove-subtask.md @@ -0,0 +1,84 @@ +Remove a subtask from its parent task. + +Arguments: $ARGUMENTS + +Parse subtask ID to remove, with option to convert to standalone task. + +## Removing Subtasks + +Remove a subtask and optionally convert it back to a standalone task. + +## Argument Parsing + +- "remove subtask 5.1" +- "delete 5.1" +- "convert 5.1 to task" → remove and convert +- "5.1 standalone" → convert to standalone + +## Execution Options + +### 1. Delete Subtask +```bash +task-master remove-subtask --id=<parentId.subtaskId> +``` + +### 2. Convert to Standalone +```bash +task-master remove-subtask --id=<parentId.subtaskId> --convert +``` + +## Pre-Removal Checks + +1. **Validate Subtask** + - Verify subtask exists + - Check completion status + - Review dependencies + +2. **Impact Analysis** + - Other subtasks that depend on it + - Parent task implications + - Data that will be lost + +## Removal Process + +### For Deletion: +1. Confirm if subtask has work done +2. Update parent task estimates +3. Remove subtask and its data +4. Clean up dependencies + +### For Conversion: +1. Assign new standalone task ID +2. Preserve all task data +3. Update dependency references +4. Maintain task history + +## Smart Features + +- Warn if subtask is in-progress +- Show impact on parent task +- Preserve important data +- Update related estimates + +## Example Flows + +``` +/project:tm/remove-subtask 5.1 +→ Warning: Subtask #5.1 is in-progress +→ This will delete all subtask data +→ Parent task #5 will be updated +Confirm deletion? (y/n) + +/project:tm/remove-subtask 5.1 convert +→ Converting subtask #5.1 to standalone task #89 +→ Preserved: All task data and history +→ Updated: 2 dependency references +→ New task #89 is now independent +``` + +## Post-Removal + +- Update parent task status +- Recalculate estimates +- Show updated hierarchy +- Suggest next actions \ No newline at end of file diff --git a/assets/claude/commands/tm/remove-task/remove-task.md b/assets/claude/commands/tm/remove-task/remove-task.md new file mode 100644 index 00000000..477d4a3b --- /dev/null +++ b/assets/claude/commands/tm/remove-task/remove-task.md @@ -0,0 +1,107 @@ +Remove a task permanently from the project. + +Arguments: $ARGUMENTS (task ID) + +Delete a task and handle all its relationships properly. + +## Task Removal + +Permanently removes a task while maintaining project integrity. + +## Argument Parsing + +- "remove task 5" +- "delete 5" +- "5" → remove task 5 +- Can include "-y" for auto-confirm + +## Execution + +```bash +task-master remove-task --id=<id> [-y] +``` + +## Pre-Removal Analysis + +1. **Task Details** + - Current status + - Work completed + - Time invested + - Associated data + +2. **Relationship Check** + - Tasks that depend on this + - Dependencies this task has + - Subtasks that will be removed + - Blocking implications + +3. **Impact Assessment** + ``` + Task Removal Impact + ━━━━━━━━━━━━━━━━━━ + Task: #5 "Implement authentication" (in-progress) + Status: 60% complete (~8 hours work) + + Will affect: + - 3 tasks depend on this (will be blocked) + - Has 4 subtasks (will be deleted) + - Part of critical path + + ⚠️ This action cannot be undone + ``` + +## Smart Warnings + +- Warn if task is in-progress +- Show dependent tasks that will be blocked +- Highlight if part of critical path +- Note any completed work being lost + +## Removal Process + +1. Show comprehensive impact +2. Require confirmation (unless -y) +3. Update dependent task references +4. Remove task and subtasks +5. Clean up orphaned dependencies +6. Log removal with timestamp + +## Alternative Actions + +Suggest before deletion: +- Mark as cancelled instead +- Convert to documentation +- Archive task data +- Transfer work to another task + +## Post-Removal + +- List affected tasks +- Show broken dependencies +- Update project statistics +- Suggest dependency fixes +- Recalculate timeline + +## Example Flows + +``` +/project:tm/remove-task 5 +→ Task #5 is in-progress with 8 hours logged +→ 3 other tasks depend on this +→ Suggestion: Mark as cancelled instead? +Remove anyway? (y/n) + +/project:tm/remove-task 5 -y +→ Removed: Task #5 and 4 subtasks +→ Updated: 3 task dependencies +→ Warning: Tasks #7, #8, #9 now have missing dependency +→ Run /project:tm/fix-dependencies to resolve +``` + +## Safety Features + +- Confirmation required +- Impact preview +- Removal logging +- Suggest alternatives +- No cascade delete of dependents \ No newline at end of file diff --git a/assets/claude/commands/tm/set-status/to-cancelled.md b/assets/claude/commands/tm/set-status/to-cancelled.md new file mode 100644 index 00000000..72c73b37 --- /dev/null +++ b/assets/claude/commands/tm/set-status/to-cancelled.md @@ -0,0 +1,55 @@ +Cancel a task permanently. + +Arguments: $ARGUMENTS (task ID) + +## Cancelling a Task + +This status indicates a task is no longer needed and won't be completed. + +## Valid Reasons for Cancellation + +- Requirements changed +- Feature deprecated +- Duplicate of another task +- Strategic pivot +- Technical approach invalidated + +## Pre-Cancellation Checks + +1. Confirm no critical dependencies +2. Check for partial implementation +3. Verify cancellation rationale +4. Document lessons learned + +## Execution + +```bash +task-master set-status --id=$ARGUMENTS --status=cancelled +``` + +## Cancellation Impact + +When cancelling: +1. **Dependency Updates** + - Notify dependent tasks + - Update project scope + - Recalculate timelines + +2. **Clean-up Actions** + - Remove related branches + - Archive any work done + - Update documentation + - Close related issues + +3. **Learning Capture** + - Document why cancelled + - Note what was learned + - Update estimation models + - Prevent future duplicates + +## Historical Preservation + +- Keep for reference +- Tag with cancellation reason +- Link to replacement if any +- Maintain audit trail \ No newline at end of file diff --git a/assets/claude/commands/tm/set-status/to-deferred.md b/assets/claude/commands/tm/set-status/to-deferred.md new file mode 100644 index 00000000..e679a8d3 --- /dev/null +++ b/assets/claude/commands/tm/set-status/to-deferred.md @@ -0,0 +1,47 @@ +Defer a task for later consideration. + +Arguments: $ARGUMENTS (task ID) + +## Deferring a Task + +This status indicates a task is valid but not currently actionable or prioritized. + +## Valid Reasons for Deferral + +- Waiting for external dependencies +- Reprioritized for future sprint +- Blocked by technical limitations +- Resource constraints +- Strategic timing considerations + +## Execution + +```bash +task-master set-status --id=$ARGUMENTS --status=deferred +``` + +## Deferral Management + +When deferring: +1. **Document Reason** + - Capture why it's being deferred + - Set reactivation criteria + - Note any partial work completed + +2. **Impact Analysis** + - Check dependent tasks + - Update project timeline + - Notify affected stakeholders + +3. **Future Planning** + - Set review reminders + - Tag for specific milestone + - Preserve context for reactivation + - Link to blocking issues + +## Smart Tracking + +- Monitor deferral duration +- Alert when criteria met +- Prevent scope creep +- Regular review cycles \ No newline at end of file diff --git a/assets/claude/commands/tm/set-status/to-done.md b/assets/claude/commands/tm/set-status/to-done.md new file mode 100644 index 00000000..9a3fd98f --- /dev/null +++ b/assets/claude/commands/tm/set-status/to-done.md @@ -0,0 +1,44 @@ +Mark a task as completed. + +Arguments: $ARGUMENTS (task ID) + +## Completing a Task + +This command validates task completion and updates project state intelligently. + +## Pre-Completion Checks + +1. Verify test strategy was followed +2. Check if all subtasks are complete +3. Validate acceptance criteria met +4. Ensure code is committed + +## Execution + +```bash +task-master set-status --id=$ARGUMENTS --status=done +``` + +## Post-Completion Actions + +1. **Update Dependencies** + - Identify newly unblocked tasks + - Update sprint progress + - Recalculate project timeline + +2. **Documentation** + - Generate completion summary + - Update CLAUDE.md with learnings + - Log implementation approach + +3. **Next Steps** + - Show newly available tasks + - Suggest logical next task + - Update velocity metrics + +## Celebration & Learning + +- Show impact of completion +- Display unblocked work +- Recognize achievement +- Capture lessons learned \ No newline at end of file diff --git a/assets/claude/commands/tm/set-status/to-in-progress.md b/assets/claude/commands/tm/set-status/to-in-progress.md new file mode 100644 index 00000000..830a67d0 --- /dev/null +++ b/assets/claude/commands/tm/set-status/to-in-progress.md @@ -0,0 +1,36 @@ +Start working on a task by setting its status to in-progress. + +Arguments: $ARGUMENTS (task ID) + +## Starting Work on Task + +This command does more than just change status - it prepares your environment for productive work. + +## Pre-Start Checks + +1. Verify dependencies are met +2. Check if another task is already in-progress +3. Ensure task details are complete +4. Validate test strategy exists + +## Execution + +```bash +task-master set-status --id=$ARGUMENTS --status=in-progress +``` + +## Environment Setup + +After setting to in-progress: +1. Create/checkout appropriate git branch +2. Open relevant documentation +3. Set up test watchers if applicable +4. Display task details and acceptance criteria +5. Show similar completed tasks for reference + +## Smart Suggestions + +- Estimated completion time based on complexity +- Related files from similar tasks +- Potential blockers to watch for +- Recommended first steps \ No newline at end of file diff --git a/assets/claude/commands/tm/set-status/to-pending.md b/assets/claude/commands/tm/set-status/to-pending.md new file mode 100644 index 00000000..fb6a6560 --- /dev/null +++ b/assets/claude/commands/tm/set-status/to-pending.md @@ -0,0 +1,32 @@ +Set a task's status to pending. + +Arguments: $ARGUMENTS (task ID) + +## Setting Task to Pending + +This moves a task back to the pending state, useful for: +- Resetting erroneously started tasks +- Deferring work that was prematurely begun +- Reorganizing sprint priorities + +## Execution + +```bash +task-master set-status --id=$ARGUMENTS --status=pending +``` + +## Validation + +Before setting to pending: +- Warn if task is currently in-progress +- Check if this will block other tasks +- Suggest documenting why it's being reset +- Preserve any work already done + +## Smart Actions + +After setting to pending: +- Update sprint planning if needed +- Notify about freed resources +- Suggest priority reassessment +- Log the status change with context \ No newline at end of file diff --git a/assets/claude/commands/tm/set-status/to-review.md b/assets/claude/commands/tm/set-status/to-review.md new file mode 100644 index 00000000..2fb77b13 --- /dev/null +++ b/assets/claude/commands/tm/set-status/to-review.md @@ -0,0 +1,40 @@ +Set a task's status to review. + +Arguments: $ARGUMENTS (task ID) + +## Marking Task for Review + +This status indicates work is complete but needs verification before final approval. + +## When to Use Review Status + +- Code complete but needs peer review +- Implementation done but needs testing +- Documentation written but needs proofreading +- Design complete but needs stakeholder approval + +## Execution + +```bash +task-master set-status --id=$ARGUMENTS --status=review +``` + +## Review Preparation + +When setting to review: +1. **Generate Review Checklist** + - Link to PR/MR if applicable + - Highlight key changes + - Note areas needing attention + - Include test results + +2. **Documentation** + - Update task with review notes + - Link relevant artifacts + - Specify reviewers if known + +3. **Smart Actions** + - Create review reminders + - Track review duration + - Suggest reviewers based on expertise + - Prepare rollback plan if needed \ No newline at end of file diff --git a/assets/claude/commands/tm/setup/install-taskmaster.md b/assets/claude/commands/tm/setup/install-taskmaster.md new file mode 100644 index 00000000..73116074 --- /dev/null +++ b/assets/claude/commands/tm/setup/install-taskmaster.md @@ -0,0 +1,117 @@ +Check if Task Master is installed and install it if needed. + +This command helps you get Task Master set up globally on your system. + +## Detection and Installation Process + +1. **Check Current Installation** + ```bash + # Check if task-master command exists + which task-master || echo "Task Master not found" + + # Check npm global packages + npm list -g task-master-ai + ``` + +2. **System Requirements Check** + ```bash + # Verify Node.js is installed + node --version + + # Verify npm is installed + npm --version + + # Check Node version (need 16+) + ``` + +3. **Install Task Master Globally** + If not installed, run: + ```bash + npm install -g task-master-ai + ``` + +4. **Verify Installation** + ```bash + # Check version + task-master --version + + # Verify command is available + which task-master + ``` + +5. **Initial Setup** + ```bash + # Initialize in current directory + task-master init + ``` + +6. **Configure AI Provider** + Ensure you have at least one AI provider API key set: + ```bash + # Check current configuration + task-master models --status + + # If no API keys found, guide setup + echo "You'll need at least one API key:" + echo "- ANTHROPIC_API_KEY for Claude" + echo "- OPENAI_API_KEY for GPT models" + echo "- PERPLEXITY_API_KEY for research" + echo "" + echo "Set them in your shell profile or .env file" + ``` + +7. **Quick Test** + ```bash + # Create a test PRD + echo "Build a simple hello world API" > test-prd.txt + + # Try parsing it + task-master parse-prd test-prd.txt -n 3 + ``` + +## Troubleshooting + +If installation fails: + +**Permission Errors:** +```bash +# Try with sudo (macOS/Linux) +sudo npm install -g task-master-ai + +# Or fix npm permissions +npm config set prefix ~/.npm-global +export PATH=~/.npm-global/bin:$PATH +``` + +**Network Issues:** +```bash +# Use different registry +npm install -g task-master-ai --registry https://registry.npmjs.org/ +``` + +**Node Version Issues:** +```bash +# Install Node 18+ via nvm +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash +nvm install 18 +nvm use 18 +``` + +## Success Confirmation + +Once installed, you should see: +``` +✅ Task Master v0.16.2 (or higher) installed +✅ Command 'task-master' available globally +✅ AI provider configured +✅ Ready to use slash commands! + +Try: /project:task-master:init your-prd.md +``` + +## Next Steps + +After installation: +1. Run `/project:utils:check-health` to verify setup +2. Configure AI providers with `/project:task-master:models` +3. Start using Task Master commands! \ No newline at end of file diff --git a/assets/claude/commands/tm/setup/quick-install-taskmaster.md b/assets/claude/commands/tm/setup/quick-install-taskmaster.md new file mode 100644 index 00000000..efd63a94 --- /dev/null +++ b/assets/claude/commands/tm/setup/quick-install-taskmaster.md @@ -0,0 +1,22 @@ +Quick install Task Master globally if not already installed. + +Execute this streamlined installation: + +```bash +# Check and install in one command +task-master --version 2>/dev/null || npm install -g task-master-ai + +# Verify installation +task-master --version + +# Quick setup check +task-master models --status || echo "Note: You'll need to set up an AI provider API key" +``` + +If you see "command not found" after installation, you may need to: +1. Restart your terminal +2. Or add npm global bin to PATH: `export PATH=$(npm bin -g):$PATH` + +Once installed, you can use all the Task Master commands! + +Quick test: Run `/project:help` to see all available commands. \ No newline at end of file diff --git a/assets/claude/commands/tm/show/show-task.md b/assets/claude/commands/tm/show/show-task.md new file mode 100644 index 00000000..789c804f --- /dev/null +++ b/assets/claude/commands/tm/show/show-task.md @@ -0,0 +1,82 @@ +Show detailed task information with rich context and insights. + +Arguments: $ARGUMENTS + +## Enhanced Task Display + +Parse arguments to determine what to show and how. + +### 1. **Smart Task Selection** + +Based on $ARGUMENTS: +- Number → Show specific task with full context +- "current" → Show active in-progress task(s) +- "next" → Show recommended next task +- "blocked" → Show all blocked tasks with reasons +- "critical" → Show critical path tasks +- Multiple IDs → Comparative view + +### 2. **Contextual Information** + +For each task, intelligently include: + +**Core Details** +- Full task information (id, title, description, details) +- Current status with history +- Test strategy and acceptance criteria +- Priority and complexity analysis + +**Relationships** +- Dependencies (what it needs) +- Dependents (what needs it) +- Parent/subtask hierarchy +- Related tasks (similar work) + +**Time Intelligence** +- Created/updated timestamps +- Time in current status +- Estimated vs actual time +- Historical completion patterns + +### 3. **Visual Enhancements** + +``` +📋 Task #45: Implement User Authentication +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Status: 🟡 in-progress (2 hours) +Priority: 🔴 High | Complexity: 73/100 + +Dependencies: ✅ #41, ✅ #42, ⏳ #43 (blocked) +Blocks: #46, #47, #52 + +Progress: ████████░░ 80% complete + +Recent Activity: +- 2h ago: Status changed to in-progress +- 4h ago: Dependency #42 completed +- Yesterday: Task expanded with 3 subtasks +``` + +### 4. **Intelligent Insights** + +Based on task analysis: +- **Risk Assessment**: Complexity vs time remaining +- **Bottleneck Analysis**: Is this blocking critical work? +- **Recommendation**: Suggested approach or concerns +- **Similar Tasks**: How others completed similar work + +### 5. **Action Suggestions** + +Context-aware next steps: +- If blocked → Show how to unblock +- If complex → Suggest expansion +- If in-progress → Show completion checklist +- If done → Show dependent tasks ready to start + +### 6. **Multi-Task View** + +When showing multiple tasks: +- Common dependencies +- Optimal completion order +- Parallel work opportunities +- Combined complexity analysis \ No newline at end of file diff --git a/assets/claude/commands/tm/status/project-status.md b/assets/claude/commands/tm/status/project-status.md new file mode 100644 index 00000000..c62bcc24 --- /dev/null +++ b/assets/claude/commands/tm/status/project-status.md @@ -0,0 +1,64 @@ +Enhanced status command with comprehensive project insights. + +Arguments: $ARGUMENTS + +## Intelligent Status Overview + +### 1. **Executive Summary** +Quick dashboard view: +- 🏃 Active work (in-progress tasks) +- 📊 Progress metrics (% complete, velocity) +- 🚧 Blockers and risks +- ⏱️ Time analysis (estimated vs actual) +- 🎯 Sprint/milestone progress + +### 2. **Contextual Analysis** + +Based on $ARGUMENTS, focus on: +- "sprint" → Current sprint progress and burndown +- "blocked" → Dependency chains and resolution paths +- "team" → Task distribution and workload +- "timeline" → Schedule adherence and projections +- "risk" → High complexity or overdue items + +### 3. **Smart Insights** + +**Workflow Health:** +- Idle tasks (in-progress > 24h without updates) +- Bottlenecks (multiple tasks waiting on same dependency) +- Quick wins (low complexity, high impact) + +**Predictive Analytics:** +- Completion projections based on velocity +- Risk of missing deadlines +- Recommended task order for optimal flow + +### 4. **Visual Intelligence** + +Dynamic visualization based on data: +``` +Sprint Progress: ████████░░ 80% (16/20 tasks) +Velocity Trend: ↗️ +15% this week +Blocked Tasks: 🔴 3 critical path items + +Priority Distribution: +High: ████████ 8 tasks (2 blocked) +Medium: ████░░░░ 4 tasks +Low: ██░░░░░░ 2 tasks +``` + +### 5. **Actionable Recommendations** + +Based on analysis: +1. **Immediate actions** (unblock critical path) +2. **Today's focus** (optimal task sequence) +3. **Process improvements** (recurring patterns) +4. **Resource needs** (skills, time, dependencies) + +### 6. **Historical Context** + +Compare to previous periods: +- Velocity changes +- Pattern recognition +- Improvement areas +- Success patterns to repeat \ No newline at end of file diff --git a/assets/claude/commands/tm/sync-readme/sync-readme.md b/assets/claude/commands/tm/sync-readme/sync-readme.md new file mode 100644 index 00000000..7f319e25 --- /dev/null +++ b/assets/claude/commands/tm/sync-readme/sync-readme.md @@ -0,0 +1,117 @@ +Export tasks to README.md with professional formatting. + +Arguments: $ARGUMENTS + +Generate a well-formatted README with current task information. + +## README Synchronization + +Creates or updates README.md with beautifully formatted task information. + +## Argument Parsing + +Optional filters: +- "pending" → Only pending tasks +- "with-subtasks" → Include subtask details +- "by-priority" → Group by priority +- "sprint" → Current sprint only + +## Execution + +```bash +task-master sync-readme [--with-subtasks] [--status=<status>] +``` + +## README Generation + +### 1. **Project Header** +```markdown +# Project Name + +## 📋 Task Progress + +Last Updated: 2024-01-15 10:30 AM + +### Summary +- Total Tasks: 45 +- Completed: 15 (33%) +- In Progress: 5 (11%) +- Pending: 25 (56%) +``` + +### 2. **Task Sections** +Organized by status or priority: +- Progress indicators +- Task descriptions +- Dependencies noted +- Time estimates + +### 3. **Visual Elements** +- Progress bars +- Status badges +- Priority indicators +- Completion checkmarks + +## Smart Features + +1. **Intelligent Grouping** + - By feature area + - By sprint/milestone + - By assigned developer + - By priority + +2. **Progress Tracking** + - Overall completion + - Sprint velocity + - Burndown indication + - Time tracking + +3. **Formatting Options** + - GitHub-flavored markdown + - Task checkboxes + - Collapsible sections + - Table format available + +## Example Output + +```markdown +## 🚀 Current Sprint + +### In Progress +- [ ] 🔄 #5 **Implement user authentication** (60% complete) + - Dependencies: API design (#3 ✅) + - Subtasks: 4 (2 completed) + - Est: 8h / Spent: 5h + +### Pending (High Priority) +- [ ] ⚡ #8 **Create dashboard UI** + - Blocked by: #5 + - Complexity: High + - Est: 12h +``` + +## Customization + +Based on arguments: +- Include/exclude sections +- Detail level control +- Custom grouping +- Filter by criteria + +## Post-Sync + +After generation: +1. Show diff preview +2. Backup existing README +3. Write new content +4. Commit reminder +5. Update timestamp + +## Integration + +Works well with: +- Git workflows +- CI/CD pipelines +- Project documentation +- Team updates +- Client reports \ No newline at end of file diff --git a/assets/claude/commands/tm/tm-main.md b/assets/claude/commands/tm/tm-main.md new file mode 100644 index 00000000..92946364 --- /dev/null +++ b/assets/claude/commands/tm/tm-main.md @@ -0,0 +1,146 @@ +# Task Master Command Reference + +Comprehensive command structure for Task Master integration with Claude Code. + +## Command Organization + +Commands are organized hierarchically to match Task Master's CLI structure while providing enhanced Claude Code integration. + +## Project Setup & Configuration + +### `/project:tm/init` +- `init-project` - Initialize new project (handles PRD files intelligently) +- `init-project-quick` - Quick setup with auto-confirmation (-y flag) + +### `/project:tm/models` +- `view-models` - View current AI model configuration +- `setup-models` - Interactive model configuration +- `set-main` - Set primary generation model +- `set-research` - Set research model +- `set-fallback` - Set fallback model + +## Task Generation + +### `/project:tm/parse-prd` +- `parse-prd` - Generate tasks from PRD document +- `parse-prd-with-research` - Enhanced parsing with research mode + +### `/project:tm/generate` +- `generate-tasks` - Create individual task files from tasks.json + +## Task Management + +### `/project:tm/list` +- `list-tasks` - Smart listing with natural language filters +- `list-tasks-with-subtasks` - Include subtasks in hierarchical view +- `list-tasks-by-status` - Filter by specific status + +### `/project:tm/set-status` +- `to-pending` - Reset task to pending +- `to-in-progress` - Start working on task +- `to-done` - Mark task complete +- `to-review` - Submit for review +- `to-deferred` - Defer task +- `to-cancelled` - Cancel task + +### `/project:tm/sync-readme` +- `sync-readme` - Export tasks to README.md with formatting + +### `/project:tm/update` +- `update-task` - Update tasks with natural language +- `update-tasks-from-id` - Update multiple tasks from a starting point +- `update-single-task` - Update specific task + +### `/project:tm/add-task` +- `add-task` - Add new task with AI assistance + +### `/project:tm/remove-task` +- `remove-task` - Remove task with confirmation + +## Subtask Management + +### `/project:tm/add-subtask` +- `add-subtask` - Add new subtask to parent +- `convert-task-to-subtask` - Convert existing task to subtask + +### `/project:tm/remove-subtask` +- `remove-subtask` - Remove subtask (with optional conversion) + +### `/project:tm/clear-subtasks` +- `clear-subtasks` - Clear subtasks from specific task +- `clear-all-subtasks` - Clear all subtasks globally + +## Task Analysis & Breakdown + +### `/project:tm/analyze-complexity` +- `analyze-complexity` - Analyze and generate expansion recommendations + +### `/project:tm/complexity-report` +- `complexity-report` - Display complexity analysis report + +### `/project:tm/expand` +- `expand-task` - Break down specific task +- `expand-all-tasks` - Expand all eligible tasks +- `with-research` - Enhanced expansion + +## Task Navigation + +### `/project:tm/next` +- `next-task` - Intelligent next task recommendation + +### `/project:tm/show` +- `show-task` - Display detailed task information + +### `/project:tm/status` +- `project-status` - Comprehensive project dashboard + +## Dependency Management + +### `/project:tm/add-dependency` +- `add-dependency` - Add task dependency + +### `/project:tm/remove-dependency` +- `remove-dependency` - Remove task dependency + +### `/project:tm/validate-dependencies` +- `validate-dependencies` - Check for dependency issues + +### `/project:tm/fix-dependencies` +- `fix-dependencies` - Automatically fix dependency problems + +## Workflows & Automation + +### `/project:tm/workflows` +- `smart-workflow` - Context-aware intelligent workflow execution +- `command-pipeline` - Chain multiple commands together +- `auto-implement-tasks` - Advanced auto-implementation with code generation + +## Utilities + +### `/project:tm/utils` +- `analyze-project` - Deep project analysis and insights + +### `/project:tm/setup` +- `install-taskmaster` - Comprehensive installation guide +- `quick-install-taskmaster` - One-line global installation + +## Usage Patterns + +### Natural Language +Most commands accept natural language arguments: +``` +/project:tm/add-task create user authentication system +/project:tm/update mark all API tasks as high priority +/project:tm/list show blocked tasks +``` + +### ID-Based Commands +Commands requiring IDs intelligently parse from $ARGUMENTS: +``` +/project:tm/show 45 +/project:tm/expand 23 +/project:tm/set-status/to-done 67 +``` + +### Smart Defaults +Commands provide intelligent defaults and suggestions based on context. \ No newline at end of file diff --git a/assets/claude/commands/tm/update/update-single-task.md b/assets/claude/commands/tm/update/update-single-task.md new file mode 100644 index 00000000..9bab5fac --- /dev/null +++ b/assets/claude/commands/tm/update/update-single-task.md @@ -0,0 +1,119 @@ +Update a single specific task with new information. + +Arguments: $ARGUMENTS + +Parse task ID and update details. + +## Single Task Update + +Precisely update one task with AI assistance to maintain consistency. + +## Argument Parsing + +Natural language updates: +- "5: add caching requirement" +- "update 5 to include error handling" +- "task 5 needs rate limiting" +- "5 change priority to high" + +## Execution + +```bash +task-master update-task --id=<id> --prompt="<context>" +``` + +## Update Types + +### 1. **Content Updates** +- Enhance description +- Add requirements +- Clarify details +- Update acceptance criteria + +### 2. **Metadata Updates** +- Change priority +- Adjust time estimates +- Update complexity +- Modify dependencies + +### 3. **Strategic Updates** +- Revise approach +- Change test strategy +- Update implementation notes +- Adjust subtask needs + +## AI-Powered Updates + +The AI: +1. **Understands Context** + - Reads current task state + - Identifies update intent + - Maintains consistency + - Preserves important info + +2. **Applies Changes** + - Updates relevant fields + - Keeps style consistent + - Adds without removing + - Enhances clarity + +3. **Validates Results** + - Checks coherence + - Verifies completeness + - Maintains relationships + - Suggests related updates + +## Example Updates + +``` +/project:tm/update/single 5: add rate limiting +→ Updating Task #5: "Implement API endpoints" + +Current: Basic CRUD endpoints +Adding: Rate limiting requirements + +Updated sections: +✓ Description: Added rate limiting mention +✓ Details: Added specific limits (100/min) +✓ Test Strategy: Added rate limit tests +✓ Complexity: Increased from 5 to 6 +✓ Time Estimate: Increased by 2 hours + +Suggestion: Also update task #6 (API Gateway) for consistency? +``` + +## Smart Features + +1. **Incremental Updates** + - Adds without overwriting + - Preserves work history + - Tracks what changed + - Shows diff view + +2. **Consistency Checks** + - Related task alignment + - Subtask compatibility + - Dependency validity + - Timeline impact + +3. **Update History** + - Timestamp changes + - Track who/what updated + - Reason for update + - Previous versions + +## Field-Specific Updates + +Quick syntax for specific fields: +- "5 priority:high" → Update priority only +- "5 add-time:4h" → Add to time estimate +- "5 status:review" → Change status +- "5 depends:3,4" → Add dependencies + +## Post-Update + +- Show updated task +- Highlight changes +- Check related tasks +- Update suggestions +- Timeline adjustments \ No newline at end of file diff --git a/assets/claude/commands/tm/update/update-task.md b/assets/claude/commands/tm/update/update-task.md new file mode 100644 index 00000000..a654d5eb --- /dev/null +++ b/assets/claude/commands/tm/update/update-task.md @@ -0,0 +1,72 @@ +Update tasks with intelligent field detection and bulk operations. + +Arguments: $ARGUMENTS + +## Intelligent Task Updates + +Parse arguments to determine update intent and execute smartly. + +### 1. **Natural Language Processing** + +Understand update requests like: +- "mark 23 as done" → Update status to done +- "increase priority of 45" → Set priority to high +- "add dependency on 12 to task 34" → Add dependency +- "tasks 20-25 need review" → Bulk status update +- "all API tasks high priority" → Pattern-based update + +### 2. **Smart Field Detection** + +Automatically detect what to update: +- Status keywords: done, complete, start, pause, review +- Priority changes: urgent, high, low, deprioritize +- Dependency updates: depends on, blocks, after +- Assignment: assign to, owner, responsible +- Time: estimate, spent, deadline + +### 3. **Bulk Operations** + +Support for multiple task updates: +``` +Examples: +- "complete tasks 12, 15, 18" +- "all pending auth tasks to in-progress" +- "increase priority for tasks blocking 45" +- "defer all documentation tasks" +``` + +### 4. **Contextual Validation** + +Before updating, check: +- Status transitions are valid +- Dependencies don't create cycles +- Priority changes make sense +- Bulk updates won't break project flow + +Show preview: +``` +Update Preview: +───────────────── +Tasks to update: #23, #24, #25 +Change: status → in-progress +Impact: Will unblock tasks #30, #31 +Warning: Task #24 has unmet dependencies +``` + +### 5. **Smart Suggestions** + +Based on update: +- Completing task? → Show newly unblocked tasks +- Changing priority? → Show impact on sprint +- Adding dependency? → Check for conflicts +- Bulk update? → Show summary of changes + +### 6. **Workflow Integration** + +After updates: +- Auto-update dependent task states +- Trigger status recalculation +- Update sprint/milestone progress +- Log changes with context + +Result: Flexible, intelligent task updates with safety checks. \ No newline at end of file diff --git a/assets/claude/commands/tm/update/update-tasks-from-id.md b/assets/claude/commands/tm/update/update-tasks-from-id.md new file mode 100644 index 00000000..1085352d --- /dev/null +++ b/assets/claude/commands/tm/update/update-tasks-from-id.md @@ -0,0 +1,108 @@ +Update multiple tasks starting from a specific ID. + +Arguments: $ARGUMENTS + +Parse starting task ID and update context. + +## Bulk Task Updates + +Update multiple related tasks based on new requirements or context changes. + +## Argument Parsing + +- "from 5: add security requirements" +- "5 onwards: update API endpoints" +- "starting at 5: change to use new framework" + +## Execution + +```bash +task-master update --from=<id> --prompt="<context>" +``` + +## Update Process + +### 1. **Task Selection** +Starting from specified ID: +- Include the task itself +- Include all dependent tasks +- Include related subtasks +- Smart boundary detection + +### 2. **Context Application** +AI analyzes the update context and: +- Identifies what needs changing +- Maintains consistency +- Preserves completed work +- Updates related information + +### 3. **Intelligent Updates** +- Modify descriptions appropriately +- Update test strategies +- Adjust time estimates +- Revise dependencies if needed + +## Smart Features + +1. **Scope Detection** + - Find natural task groupings + - Identify related features + - Stop at logical boundaries + - Avoid over-updating + +2. **Consistency Maintenance** + - Keep naming conventions + - Preserve relationships + - Update cross-references + - Maintain task flow + +3. **Change Preview** + ``` + Bulk Update Preview + ━━━━━━━━━━━━━━━━━━ + Starting from: Task #5 + Tasks to update: 8 tasks + 12 subtasks + + Context: "add security requirements" + + Changes will include: + - Add security sections to descriptions + - Update test strategies for security + - Add security-related subtasks where needed + - Adjust time estimates (+20% average) + + Continue? (y/n) + ``` + +## Example Updates + +``` +/project:tm/update/from-id 5: change database to PostgreSQL +→ Analyzing impact starting from task #5 +→ Found 6 related tasks to update +→ Updates will maintain consistency +→ Preview changes? (y/n) + +Applied updates: +✓ Task #5: Updated connection logic references +✓ Task #6: Changed migration approach +✓ Task #7: Updated query syntax notes +✓ Task #8: Revised testing strategy +✓ Task #9: Updated deployment steps +✓ Task #12: Changed backup procedures +``` + +## Safety Features + +- Preview all changes +- Selective confirmation +- Rollback capability +- Change logging +- Validation checks + +## Post-Update + +- Summary of changes +- Consistency verification +- Suggest review tasks +- Update timeline if needed \ No newline at end of file diff --git a/assets/claude/commands/tm/utils/analyze-project.md b/assets/claude/commands/tm/utils/analyze-project.md new file mode 100644 index 00000000..92622044 --- /dev/null +++ b/assets/claude/commands/tm/utils/analyze-project.md @@ -0,0 +1,97 @@ +Advanced project analysis with actionable insights and recommendations. + +Arguments: $ARGUMENTS + +## Comprehensive Project Analysis + +Multi-dimensional analysis based on requested focus area. + +### 1. **Analysis Modes** + +Based on $ARGUMENTS: +- "velocity" → Sprint velocity and trends +- "quality" → Code quality metrics +- "risk" → Risk assessment and mitigation +- "dependencies" → Dependency graph analysis +- "team" → Workload and skill distribution +- "architecture" → System design coherence +- Default → Full spectrum analysis + +### 2. **Velocity Analytics** + +``` +📊 Velocity Analysis +━━━━━━━━━━━━━━━━━━━ +Current Sprint: 24 points/week ↗️ +20% +Rolling Average: 20 points/week +Efficiency: 85% (17/20 tasks on time) + +Bottlenecks Detected: +- Code review delays (avg 4h wait) +- Test environment availability +- Dependency on external team + +Recommendations: +1. Implement parallel review process +2. Add staging environment +3. Mock external dependencies +``` + +### 3. **Risk Assessment** + +**Technical Risks** +- High complexity tasks without backup assignee +- Single points of failure in architecture +- Insufficient test coverage in critical paths +- Technical debt accumulation rate + +**Project Risks** +- Critical path dependencies +- Resource availability gaps +- Deadline feasibility analysis +- Scope creep indicators + +### 4. **Dependency Intelligence** + +Visual dependency analysis: +``` +Critical Path: +#12 → #15 → #23 → #45 → #50 (20 days) + ↘ #24 → #46 ↗ + +Optimization: Parallelize #15 and #24 +Time Saved: 3 days +``` + +### 5. **Quality Metrics** + +**Code Quality** +- Test coverage trends +- Complexity scores +- Technical debt ratio +- Review feedback patterns + +**Process Quality** +- Rework frequency +- Bug introduction rate +- Time to resolution +- Knowledge distribution + +### 6. **Predictive Insights** + +Based on patterns: +- Completion probability by deadline +- Resource needs projection +- Risk materialization likelihood +- Suggested interventions + +### 7. **Executive Dashboard** + +High-level summary with: +- Health score (0-100) +- Top 3 risks +- Top 3 opportunities +- Recommended actions +- Success probability + +Result: Data-driven decisions with clear action paths. \ No newline at end of file diff --git a/assets/claude/commands/tm/validate-dependencies/validate-dependencies.md b/assets/claude/commands/tm/validate-dependencies/validate-dependencies.md new file mode 100644 index 00000000..aaf4eb46 --- /dev/null +++ b/assets/claude/commands/tm/validate-dependencies/validate-dependencies.md @@ -0,0 +1,71 @@ +Validate all task dependencies for issues. + +## Dependency Validation + +Comprehensive check for dependency problems across the entire project. + +## Execution + +```bash +task-master validate-dependencies +``` + +## Validation Checks + +1. **Circular Dependencies** + - A depends on B, B depends on A + - Complex circular chains + - Self-dependencies + +2. **Missing Dependencies** + - References to non-existent tasks + - Deleted task references + - Invalid task IDs + +3. **Logical Issues** + - Completed tasks depending on pending + - Cancelled tasks in dependency chains + - Impossible sequences + +4. **Complexity Warnings** + - Over-complex dependency chains + - Too many dependencies per task + - Bottleneck tasks + +## Smart Analysis + +The validation provides: +- Visual dependency graph +- Critical path analysis +- Bottleneck identification +- Suggested optimizations + +## Report Format + +``` +Dependency Validation Report +━━━━━━━━━━━━━━━━━━━━━━━━━━ +✅ No circular dependencies found +⚠️ 2 warnings found: + - Task #23 has 7 dependencies (consider breaking down) + - Task #45 blocks 5 other tasks (potential bottleneck) +❌ 1 error found: + - Task #67 depends on deleted task #66 + +Critical Path: #1 → #5 → #23 → #45 → #50 (15 days) +``` + +## Actionable Output + +For each issue found: +- Clear description +- Impact assessment +- Suggested fix +- Command to resolve + +## Next Steps + +After validation: +- Run `/project:tm/fix-dependencies` to auto-fix +- Manually adjust problematic dependencies +- Rerun to verify fixes \ No newline at end of file diff --git a/assets/claude/commands/tm/workflows/auto-implement-tasks.md b/assets/claude/commands/tm/workflows/auto-implement-tasks.md new file mode 100644 index 00000000..20abc950 --- /dev/null +++ b/assets/claude/commands/tm/workflows/auto-implement-tasks.md @@ -0,0 +1,97 @@ +Enhanced auto-implementation with intelligent code generation and testing. + +Arguments: $ARGUMENTS + +## Intelligent Auto-Implementation + +Advanced implementation with context awareness and quality checks. + +### 1. **Pre-Implementation Analysis** + +Before starting: +- Analyze task complexity and requirements +- Check codebase patterns and conventions +- Identify similar completed tasks +- Assess test coverage needs +- Detect potential risks + +### 2. **Smart Implementation Strategy** + +Based on task type and context: + +**Feature Tasks** +1. Research existing patterns +2. Design component architecture +3. Implement with tests +4. Integrate with system +5. Update documentation + +**Bug Fix Tasks** +1. Reproduce issue +2. Identify root cause +3. Implement minimal fix +4. Add regression tests +5. Verify side effects + +**Refactoring Tasks** +1. Analyze current structure +2. Plan incremental changes +3. Maintain test coverage +4. Refactor step-by-step +5. Verify behavior unchanged + +### 3. **Code Intelligence** + +**Pattern Recognition** +- Learn from existing code +- Follow team conventions +- Use preferred libraries +- Match style guidelines + +**Test-Driven Approach** +- Write tests first when possible +- Ensure comprehensive coverage +- Include edge cases +- Performance considerations + +### 4. **Progressive Implementation** + +Step-by-step with validation: +``` +Step 1/5: Setting up component structure ✓ +Step 2/5: Implementing core logic ✓ +Step 3/5: Adding error handling ⚡ (in progress) +Step 4/5: Writing tests ⏳ +Step 5/5: Integration testing ⏳ + +Current: Adding try-catch blocks and validation... +``` + +### 5. **Quality Assurance** + +Automated checks: +- Linting and formatting +- Test execution +- Type checking +- Dependency validation +- Performance analysis + +### 6. **Smart Recovery** + +If issues arise: +- Diagnostic analysis +- Suggestion generation +- Fallback strategies +- Manual intervention points +- Learning from failures + +### 7. **Post-Implementation** + +After completion: +- Generate PR description +- Update documentation +- Log lessons learned +- Suggest follow-up tasks +- Update task relationships + +Result: High-quality, production-ready implementations. \ No newline at end of file diff --git a/assets/claude/commands/tm/workflows/command-pipeline.md b/assets/claude/commands/tm/workflows/command-pipeline.md new file mode 100644 index 00000000..83080018 --- /dev/null +++ b/assets/claude/commands/tm/workflows/command-pipeline.md @@ -0,0 +1,77 @@ +Execute a pipeline of commands based on a specification. + +Arguments: $ARGUMENTS + +## Command Pipeline Execution + +Parse pipeline specification from arguments. Supported formats: + +### Simple Pipeline +`init → expand-all → sprint-plan` + +### Conditional Pipeline +`status → if:pending>10 → sprint-plan → else → next` + +### Iterative Pipeline +`for:pending-tasks → expand → complexity-check` + +### Smart Pipeline Patterns + +**1. Project Setup Pipeline** +``` +init [prd] → +expand-all → +complexity-report → +sprint-plan → +show first-sprint +``` + +**2. Daily Work Pipeline** +``` +standup → +if:in-progress → continue → +else → next → start +``` + +**3. Task Completion Pipeline** +``` +complete [id] → +git-commit → +if:blocked-tasks-freed → show-freed → +next +``` + +**4. Quality Check Pipeline** +``` +list in-progress → +for:each → check-idle-time → +if:idle>1day → prompt-update +``` + +### Pipeline Features + +**Variables** +- Store results: `status → $count=pending-count` +- Use in conditions: `if:$count>10` +- Pass between commands: `expand $high-priority-tasks` + +**Error Handling** +- On failure: `try:complete → catch:show-blockers` +- Skip on error: `optional:test-run` +- Retry logic: `retry:3:commit` + +**Parallel Execution** +- Parallel branches: `[analyze | test | lint]` +- Join results: `parallel → join:report` + +### Execution Flow + +1. Parse pipeline specification +2. Validate command sequence +3. Execute with state passing +4. Handle conditions and loops +5. Aggregate results +6. Show summary + +This enables complex workflows like: +`parse-prd → expand-all → filter:complex>70 → assign:senior → sprint-plan:weighted` \ No newline at end of file diff --git a/assets/claude/commands/tm/workflows/smart-workflow.md b/assets/claude/commands/tm/workflows/smart-workflow.md new file mode 100644 index 00000000..56eb28d4 --- /dev/null +++ b/assets/claude/commands/tm/workflows/smart-workflow.md @@ -0,0 +1,55 @@ +Execute an intelligent workflow based on current project state and recent commands. + +This command analyzes: +1. Recent commands you've run +2. Current project state +3. Time of day / day of week +4. Your working patterns + +Arguments: $ARGUMENTS + +## Intelligent Workflow Selection + +Based on context, I'll determine the best workflow: + +### Context Analysis +- Previous command executed +- Current task states +- Unfinished work from last session +- Your typical patterns + +### Smart Execution + +If last command was: +- `status` → Likely starting work → Run daily standup +- `complete` → Task finished → Find next task +- `list pending` → Planning → Suggest sprint planning +- `expand` → Breaking down work → Show complexity analysis +- `init` → New project → Show onboarding workflow + +If no recent commands: +- Morning? → Daily standup workflow +- Many pending tasks? → Sprint planning +- Tasks blocked? → Dependency resolution +- Friday? → Weekly review + +### Workflow Composition + +I'll chain appropriate commands: +1. Analyze current state +2. Execute primary workflow +3. Suggest follow-up actions +4. Prepare environment for coding + +### Learning Mode + +This command learns from your patterns: +- Track command sequences +- Note time preferences +- Remember common workflows +- Adapt to your style + +Example flows detected: +- Morning: standup → next → start +- After lunch: status → continue task +- End of day: complete → commit → status \ No newline at end of file diff --git a/package.json b/package.json index f73eb3a6..25d55c4f 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,8 @@ }, "optionalDependencies": { "@anthropic-ai/claude-code": "^1.0.25", - "ai-sdk-provider-gemini-cli": "^0.0.4" + "ai-sdk-provider-gemini-cli": "^0.0.4", + "@biomejs/cli-linux-x64": "^1.9.4" }, "engines": { "node": ">=18.0.0" diff --git a/scripts/modules/commands.js b/scripts/modules/commands.js index 65970c8a..63bc86a5 100644 --- a/scripts/modules/commands.js +++ b/scripts/modules/commands.js @@ -4021,10 +4021,6 @@ Examples: projectRoot, profileConfig ); - if (typeof profileConfig.onAddRulesProfile === 'function') { - const assetsDir = path.join(projectRoot, 'assets'); - profileConfig.onAddRulesProfile(projectRoot, assetsDir); - } console.log( chalk.blue(`Completed adding rules for profile: ${profile}`) ); @@ -4054,37 +4050,27 @@ Examples: // Print summary for additions if (action === RULES_ACTIONS.ADD && addResults.length > 0) { - const { - allSuccessfulProfiles, - totalSuccess, - totalFailed, - simpleProfiles - } = categorizeProfileResults(addResults); + const { allSuccessfulProfiles, totalSuccess, totalFailed } = + categorizeProfileResults(addResults); if (allSuccessfulProfiles.length > 0) { console.log( chalk.green( - `\nSuccessfully added rules for: ${allSuccessfulProfiles.join(', ')}` + `\nSuccessfully processed profiles: ${allSuccessfulProfiles.join(', ')}` ) ); - // Create a more descriptive summary - if (totalSuccess > 0 && simpleProfiles.length > 0) { + // Create a descriptive summary + if (totalSuccess > 0) { console.log( chalk.green( - `Total: ${totalSuccess} rules added, ${totalFailed} failed, ${simpleProfiles.length} integration guide(s) copied.` + `Total: ${totalSuccess} files processed, ${totalFailed} failed.` ) ); - } else if (totalSuccess > 0) { + } else { console.log( chalk.green( - `Total: ${totalSuccess} rules added, ${totalFailed} failed.` - ) - ); - } else if (simpleProfiles.length > 0) { - console.log( - chalk.green( - `Total: ${simpleProfiles.length} integration guide(s) copied.` + `Total: ${allSuccessfulProfiles.length} profile(s) set up successfully.` ) ); } diff --git a/src/constants/profiles.js b/src/constants/profiles.js index 4d800e05..861ed406 100644 --- a/src/constants/profiles.js +++ b/src/constants/profiles.js @@ -1,5 +1,5 @@ /** - * @typedef {'claude' | 'cline' | 'codex' | 'cursor' | 'roo' | 'trae' | 'windsurf' | 'vscode'} RulesProfile + * @typedef {'claude' | 'cline' | 'codex' | 'cursor' | 'gemini' | 'roo' | 'trae' | 'windsurf' | 'vscode'} RulesProfile */ /** @@ -14,6 +14,7 @@ * - cline: Cline IDE rules * - codex: Codex integration * - cursor: Cursor IDE rules + * - gemini: Gemini integration * - roo: Roo Code IDE rules * - trae: Trae IDE rules * - vscode: VS Code with GitHub Copilot integration @@ -29,6 +30,7 @@ export const RULE_PROFILES = [ 'cline', 'codex', 'cursor', + 'gemini', 'roo', 'trae', 'vscode', diff --git a/src/profiles/base-profile.js b/src/profiles/base-profile.js index 1ef63507..6f6add59 100644 --- a/src/profiles/base-profile.js +++ b/src/profiles/base-profile.js @@ -16,8 +16,9 @@ import path from 'path'; * @param {string} [editorConfig.targetExtension='.md'] - Target file extension * @param {Object} [editorConfig.toolMappings={}] - Tool name mappings * @param {Array} [editorConfig.customReplacements=[]] - Custom text replacements - * @param {Object} [editorConfig.customFileMap={}] - Custom file name mappings + * @param {Object} [editorConfig.fileMap={}] - Custom file name mappings * @param {boolean} [editorConfig.supportsRulesSubdirectories=false] - Whether to use taskmaster/ subdirectory for taskmaster-specific rules (only Cursor uses this by default) + * @param {boolean} [editorConfig.includeDefaultRules=true] - Whether to include default rule files * @param {Function} [editorConfig.onAdd] - Lifecycle hook for profile addition * @param {Function} [editorConfig.onRemove] - Lifecycle hook for profile removal * @param {Function} [editorConfig.onPostConvert] - Lifecycle hook for post-conversion @@ -29,34 +30,38 @@ export function createProfile(editorConfig) { displayName = name, url, docsUrl, - profileDir, + profileDir = `.${name.toLowerCase()}`, rulesDir = `${profileDir}/rules`, mcpConfig = true, - mcpConfigName = 'mcp.json', + mcpConfigName = mcpConfig ? 'mcp.json' : null, fileExtension = '.mdc', targetExtension = '.md', toolMappings = {}, customReplacements = [], - customFileMap = {}, + fileMap = {}, supportsRulesSubdirectories = false, + includeDefaultRules = true, onAdd, onRemove, onPostConvert } = editorConfig; - const mcpConfigPath = `${profileDir}/${mcpConfigName}`; + const mcpConfigPath = mcpConfigName ? `${profileDir}/${mcpConfigName}` : null; // Standard file mapping with custom overrides // Use taskmaster subdirectory only if profile supports it const taskmasterPrefix = supportsRulesSubdirectories ? 'taskmaster/' : ''; const defaultFileMap = { - 'cursor_rules.mdc': `${name.toLowerCase()}_rules${targetExtension}`, - 'dev_workflow.mdc': `${taskmasterPrefix}dev_workflow${targetExtension}`, - 'self_improve.mdc': `self_improve${targetExtension}`, - 'taskmaster.mdc': `${taskmasterPrefix}taskmaster${targetExtension}` + 'rules/cursor_rules.mdc': `${name.toLowerCase()}_rules${targetExtension}`, + 'rules/dev_workflow.mdc': `${taskmasterPrefix}dev_workflow${targetExtension}`, + 'rules/self_improve.mdc': `self_improve${targetExtension}`, + 'rules/taskmaster.mdc': `${taskmasterPrefix}taskmaster${targetExtension}` }; - const fileMap = { ...defaultFileMap, ...customFileMap }; + // Build final fileMap - merge defaults with custom entries when includeDefaultRules is true + const finalFileMap = includeDefaultRules + ? { ...defaultFileMap, ...fileMap } + : fileMap; // Base global replacements that work for all editors const baseGlobalReplacements = [ @@ -187,7 +192,8 @@ export function createProfile(editorConfig) { replacement: (match, text, filePath) => { const baseName = path.basename(filePath, '.mdc'); const newFileName = - fileMap[`${baseName}.mdc`] || `${baseName}${targetExtension}`; + finalFileMap[`rules/${baseName}.mdc`] || + `${baseName}${targetExtension}`; // Update the link text to match the new filename (strip directory path for display) const newLinkText = path.basename(newFileName); // For Cursor, keep the mdc: protocol; for others, use standard relative paths @@ -201,8 +207,8 @@ export function createProfile(editorConfig) { }; function getTargetRuleFilename(sourceFilename) { - if (fileMap[sourceFilename]) { - return fileMap[sourceFilename]; + if (finalFileMap[sourceFilename]) { + return finalFileMap[sourceFilename]; } return targetExtension !== fileExtension ? sourceFilename.replace( @@ -221,7 +227,8 @@ export function createProfile(editorConfig) { mcpConfigName, mcpConfigPath, supportsRulesSubdirectories, - fileMap, + includeDefaultRules, + fileMap: finalFileMap, globalReplacements: baseGlobalReplacements, conversionConfig, getTargetRuleFilename, diff --git a/src/profiles/claude.js b/src/profiles/claude.js index acf8feb3..4ce7e557 100644 --- a/src/profiles/claude.js +++ b/src/profiles/claude.js @@ -2,58 +2,96 @@ import path from 'path'; import fs from 'fs'; import { isSilentMode, log } from '../../scripts/modules/utils.js'; +import { createProfile } from './base-profile.js'; + +// Helper function to recursively copy directory (adopted from Roo profile) +function copyRecursiveSync(src, dest) { + const exists = fs.existsSync(src); + const stats = exists && fs.statSync(src); + const isDirectory = exists && stats.isDirectory(); + if (isDirectory) { + if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true }); + fs.readdirSync(src).forEach((childItemName) => { + copyRecursiveSync( + path.join(src, childItemName), + path.join(dest, childItemName) + ); + }); + } else { + fs.copyFileSync(src, dest); + } +} + +// Helper function to recursively remove directory +function removeDirectoryRecursive(dirPath) { + if (fs.existsSync(dirPath)) { + try { + fs.rmSync(dirPath, { recursive: true, force: true }); + return true; + } catch (err) { + log('error', `Failed to remove directory ${dirPath}: ${err.message}`); + return false; + } + } + return true; +} // Lifecycle functions for Claude Code profile function onAddRulesProfile(targetDir, assetsDir) { - // Use the provided assets directory to find the source file - const sourceFile = path.join(assetsDir, 'AGENTS.md'); - const destFile = path.join(targetDir, 'CLAUDE.md'); + // Copy .claude directory recursively + const claudeSourceDir = path.join(assetsDir, 'claude'); + const claudeDestDir = path.join(targetDir, '.claude'); - if (fs.existsSync(sourceFile)) { - try { - fs.copyFileSync(sourceFile, destFile); - log('debug', `[Claude] Copied AGENTS.md to ${destFile}`); - } catch (err) { - log('error', `[Claude] Failed to copy AGENTS.md: ${err.message}`); - } + if (!fs.existsSync(claudeSourceDir)) { + log( + 'error', + `[Claude] Source directory does not exist: ${claudeSourceDir}` + ); + return; + } + + try { + copyRecursiveSync(claudeSourceDir, claudeDestDir); + log('debug', `[Claude] Copied .claude directory to ${claudeDestDir}`); + } catch (err) { + log( + 'error', + `[Claude] An error occurred during directory copy: ${err.message}` + ); } } function onRemoveRulesProfile(targetDir) { - const claudeFile = path.join(targetDir, 'CLAUDE.md'); - if (fs.existsSync(claudeFile)) { - try { - fs.rmSync(claudeFile, { force: true }); - log('debug', `[Claude] Removed CLAUDE.md from ${claudeFile}`); - } catch (err) { - log('error', `[Claude] Failed to remove CLAUDE.md: ${err.message}`); - } + // Remove .claude directory recursively + const claudeDir = path.join(targetDir, '.claude'); + if (removeDirectoryRecursive(claudeDir)) { + log('debug', `[Claude] Removed .claude directory from ${claudeDir}`); } } function onPostConvertRulesProfile(targetDir, assetsDir) { + // For Claude, post-convert is the same as add since we don't transform rules onAddRulesProfile(targetDir, assetsDir); } -// Simple filename function -function getTargetRuleFilename(sourceFilename) { - return sourceFilename; -} - -// Simple profile configuration - bypasses base-profile system -export const claudeProfile = { - profileName: 'claude', +// Create and export claude profile using the base factory +export const claudeProfile = createProfile({ + name: 'claude', displayName: 'Claude Code', + url: 'claude.ai', + docsUrl: 'docs.anthropic.com/en/docs/claude-code', profileDir: '.', // Root directory - rulesDir: '.', // No rules directory needed - mcpConfig: false, // No MCP config needed + rulesDir: '.', // No specific rules directory needed + mcpConfig: false, mcpConfigName: null, - mcpConfigPath: null, - conversionConfig: {}, - fileMap: {}, - globalReplacements: [], - getTargetRuleFilename, - onAddRulesProfile, - onRemoveRulesProfile, - onPostConvertRulesProfile -}; + includeDefaultRules: false, + fileMap: { + 'AGENTS.md': 'CLAUDE.md' + }, + onAdd: onAddRulesProfile, + onRemove: onRemoveRulesProfile, + onPostConvert: onPostConvertRulesProfile +}); + +// Export lifecycle functions separately to avoid naming conflicts +export { onAddRulesProfile, onRemoveRulesProfile, onPostConvertRulesProfile }; diff --git a/src/profiles/cline.js b/src/profiles/cline.js index 50711cb4..538a55aa 100644 --- a/src/profiles/cline.js +++ b/src/profiles/cline.js @@ -9,12 +9,5 @@ export const clineProfile = createProfile({ docsUrl: 'docs.cline.bot', profileDir: '.clinerules', rulesDir: '.clinerules', - mcpConfig: false, - mcpConfigName: 'cline_mcp_settings.json', - fileExtension: '.mdc', - targetExtension: '.md', - toolMappings: COMMON_TOOL_MAPPINGS.STANDARD, // Cline uses standard tool names - customFileMap: { - 'cursor_rules.mdc': 'cline_rules.md' - } + mcpConfig: false }); diff --git a/src/profiles/codex.js b/src/profiles/codex.js index 2392e4ad..8d2884e6 100644 --- a/src/profiles/codex.js +++ b/src/profiles/codex.js @@ -1,59 +1,18 @@ // Codex profile for rule-transformer -import path from 'path'; -import fs from 'fs'; -import { isSilentMode, log } from '../../scripts/modules/utils.js'; +import { createProfile } from './base-profile.js'; -// Lifecycle functions for Codex profile -function onAddRulesProfile(targetDir, assetsDir) { - // Use the provided assets directory to find the source file - const sourceFile = path.join(assetsDir, 'AGENTS.md'); - const destFile = path.join(targetDir, 'AGENTS.md'); - - if (fs.existsSync(sourceFile)) { - try { - fs.copyFileSync(sourceFile, destFile); - log('debug', `[Codex] Copied AGENTS.md to ${destFile}`); - } catch (err) { - log('error', `[Codex] Failed to copy AGENTS.md: ${err.message}`); - } - } -} - -function onRemoveRulesProfile(targetDir) { - const agentsFile = path.join(targetDir, 'AGENTS.md'); - if (fs.existsSync(agentsFile)) { - try { - fs.rmSync(agentsFile, { force: true }); - log('debug', `[Codex] Removed AGENTS.md from ${agentsFile}`); - } catch (err) { - log('error', `[Codex] Failed to remove AGENTS.md: ${err.message}`); - } - } -} - -function onPostConvertRulesProfile(targetDir, assetsDir) { - onAddRulesProfile(targetDir, assetsDir); -} - -// Simple filename function -function getTargetRuleFilename(sourceFilename) { - return sourceFilename; -} - -// Simple profile configuration - bypasses base-profile system -export const codexProfile = { - profileName: 'codex', +// Create and export codex profile using the base factory +export const codexProfile = createProfile({ + name: 'codex', displayName: 'Codex', + url: 'codex.ai', + docsUrl: 'platform.openai.com/docs/codex', profileDir: '.', // Root directory - rulesDir: '.', // No rules directory needed - mcpConfig: false, // No MCP config needed + rulesDir: '.', // No specific rules directory needed + mcpConfig: false, mcpConfigName: null, - mcpConfigPath: null, - conversionConfig: {}, - fileMap: {}, - globalReplacements: [], - getTargetRuleFilename, - onAddRulesProfile, - onRemoveRulesProfile, - onPostConvertRulesProfile -}; + includeDefaultRules: false, + fileMap: { + 'AGENTS.md': 'AGENTS.md' + } +}); diff --git a/src/profiles/cursor.js b/src/profiles/cursor.js index d17da8bb..8d9f7a91 100644 --- a/src/profiles/cursor.js +++ b/src/profiles/cursor.js @@ -7,15 +7,6 @@ export const cursorProfile = createProfile({ displayName: 'Cursor', url: 'cursor.so', docsUrl: 'docs.cursor.com', - profileDir: '.cursor', - rulesDir: '.cursor/rules', - mcpConfig: true, - mcpConfigName: 'mcp.json', - fileExtension: '.mdc', targetExtension: '.mdc', // Cursor keeps .mdc extension - toolMappings: COMMON_TOOL_MAPPINGS.STANDARD, - supportsRulesSubdirectories: true, - customFileMap: { - 'cursor_rules.mdc': 'cursor_rules.mdc' // Keep the same name for cursor - } + supportsRulesSubdirectories: true }); diff --git a/src/profiles/gemini.js b/src/profiles/gemini.js new file mode 100644 index 00000000..0d04d5b0 --- /dev/null +++ b/src/profiles/gemini.js @@ -0,0 +1,17 @@ +// Gemini profile for rule-transformer +import { createProfile } from './base-profile.js'; + +// Create and export gemini profile using the base factory +export const geminiProfile = createProfile({ + name: 'gemini', + displayName: 'Gemini', + url: 'codeassist.google', + docsUrl: 'github.com/google-gemini/gemini-cli', + profileDir: '.gemini', // Keep .gemini for settings.json + rulesDir: '.', // Root directory for GEMINI.md + mcpConfigName: 'settings.json', // Override default 'mcp.json' + includeDefaultRules: false, + fileMap: { + 'AGENTS.md': 'GEMINI.md' + } +}); diff --git a/src/profiles/index.js b/src/profiles/index.js index 9da3a933..01b1b9fc 100644 --- a/src/profiles/index.js +++ b/src/profiles/index.js @@ -3,6 +3,7 @@ export { claudeProfile } from './claude.js'; export { clineProfile } from './cline.js'; export { codexProfile } from './codex.js'; export { cursorProfile } from './cursor.js'; +export { geminiProfile } from './gemini.js'; export { rooProfile } from './roo.js'; export { traeProfile } from './trae.js'; export { vscodeProfile } from './vscode.js'; diff --git a/src/profiles/roo.js b/src/profiles/roo.js index 7626f14a..8d7f40b0 100644 --- a/src/profiles/roo.js +++ b/src/profiles/roo.js @@ -110,16 +110,7 @@ export const rooProfile = createProfile({ displayName: 'Roo Code', url: 'roocode.com', docsUrl: 'docs.roocode.com', - profileDir: '.roo', - rulesDir: '.roo/rules', - mcpConfig: true, - mcpConfigName: 'mcp.json', - fileExtension: '.mdc', - targetExtension: '.md', toolMappings: COMMON_TOOL_MAPPINGS.ROO_STYLE, - customFileMap: { - 'cursor_rules.mdc': 'roo_rules.md' - }, onAdd: onAddRulesProfile, onRemove: onRemoveRulesProfile, onPostConvert: onPostConvertRulesProfile diff --git a/src/profiles/trae.js b/src/profiles/trae.js index 5485478c..76445778 100644 --- a/src/profiles/trae.js +++ b/src/profiles/trae.js @@ -7,11 +7,5 @@ export const traeProfile = createProfile({ displayName: 'Trae', url: 'trae.ai', docsUrl: 'docs.trae.ai', - profileDir: '.trae', - rulesDir: '.trae/rules', - mcpConfig: false, - mcpConfigName: 'trae_mcp_settings.json', - fileExtension: '.mdc', - targetExtension: '.md', - toolMappings: COMMON_TOOL_MAPPINGS.STANDARD // Trae uses standard tool names + mcpConfig: false }); diff --git a/src/profiles/vscode.js b/src/profiles/vscode.js index 49fd763e..a5c0757c 100644 --- a/src/profiles/vscode.js +++ b/src/profiles/vscode.js @@ -7,16 +7,7 @@ export const vscodeProfile = createProfile({ displayName: 'VS Code', url: 'code.visualstudio.com', docsUrl: 'code.visualstudio.com/docs', - profileDir: '.vscode', // MCP config location rulesDir: '.github/instructions', // VS Code instructions location - mcpConfig: true, - mcpConfigName: 'mcp.json', - fileExtension: '.mdc', - targetExtension: '.md', - toolMappings: COMMON_TOOL_MAPPINGS.STANDARD, // VS Code uses standard tool names - customFileMap: { - 'cursor_rules.mdc': 'vscode_rules.md' // Rename cursor_rules to vscode_rules - }, customReplacements: [ // Core VS Code directory structure changes { from: /\.cursor\/rules/g, to: '.github/instructions' }, diff --git a/src/profiles/windsurf.js b/src/profiles/windsurf.js index 24f81925..9a0ae1cd 100644 --- a/src/profiles/windsurf.js +++ b/src/profiles/windsurf.js @@ -6,12 +6,5 @@ export const windsurfProfile = createProfile({ name: 'windsurf', displayName: 'Windsurf', url: 'windsurf.com', - docsUrl: 'docs.windsurf.com', - profileDir: '.windsurf', - rulesDir: '.windsurf/rules', - mcpConfig: true, - mcpConfigName: 'mcp.json', - fileExtension: '.mdc', - targetExtension: '.md', - toolMappings: COMMON_TOOL_MAPPINGS.STANDARD // Windsurf uses standard tool names + docsUrl: 'docs.windsurf.com' }); diff --git a/src/utils/create-mcp-config.js b/src/utils/create-mcp-config.js index d9db18e3..974ee5ec 100644 --- a/src/utils/create-mcp-config.js +++ b/src/utils/create-mcp-config.js @@ -47,15 +47,15 @@ export function setupMCPConfiguration(projectRoot, mcpConfigPath) { command: 'npx', args: ['-y', '--package=task-master-ai', 'task-master-ai'], env: { - ANTHROPIC_API_KEY: 'ANTHROPIC_API_KEY_HERE', - PERPLEXITY_API_KEY: 'PERPLEXITY_API_KEY_HERE', - OPENAI_API_KEY: 'OPENAI_API_KEY_HERE', - GOOGLE_API_KEY: 'GOOGLE_API_KEY_HERE', - XAI_API_KEY: 'XAI_API_KEY_HERE', - OPENROUTER_API_KEY: 'OPENROUTER_API_KEY_HERE', - MISTRAL_API_KEY: 'MISTRAL_API_KEY_HERE', - AZURE_OPENAI_API_KEY: 'AZURE_OPENAI_API_KEY_HERE', - OLLAMA_API_KEY: 'OLLAMA_API_KEY_HERE' + ANTHROPIC_API_KEY: 'YOUR_ANTHROPIC_API_KEY_HERE', + PERPLEXITY_API_KEY: 'YOUR_PERPLEXITY_API_KEY_HERE', + OPENAI_API_KEY: 'YOUR_OPENAI_KEY_HERE', + GOOGLE_API_KEY: 'YOUR_GOOGLE_KEY_HERE', + XAI_API_KEY: 'YOUR_XAI_KEY_HERE', + OPENROUTER_API_KEY: 'YOUR_OPENROUTER_KEY_HERE', + MISTRAL_API_KEY: 'YOUR_MISTRAL_KEY_HERE', + AZURE_OPENAI_API_KEY: 'YOUR_AZURE_KEY_HERE', + OLLAMA_API_KEY: 'YOUR_OLLAMA_API_KEY_HERE' } } }; diff --git a/src/utils/profiles.js b/src/utils/profiles.js index 50e5558d..32a2b7cf 100644 --- a/src/utils/profiles.js +++ b/src/utils/profiles.js @@ -16,24 +16,48 @@ import { RULE_PROFILES } from '../constants/profiles.js'; // ============================================================================= /** - * Detect which profiles are currently installed in the project - * @param {string} projectRoot - Project root directory - * @returns {string[]} Array of installed profile names + * Get the display name for a profile + * @param {string} profileName - The profile name + * @returns {string} - The display name + */ +export function getProfileDisplayName(profileName) { + try { + const profile = getRulesProfile(profileName); + return profile.displayName || profileName; + } catch (error) { + return profileName; + } +} + +/** + * Get installed profiles in the project directory + * @param {string} projectRoot - Project directory path + * @returns {string[]} - Array of installed profile names */ export function getInstalledProfiles(projectRoot) { const installedProfiles = []; for (const profileName of RULE_PROFILES) { - const profileConfig = getRulesProfile(profileName); - if (!profileConfig) continue; + try { + const profile = getRulesProfile(profileName); + const profileDir = path.join(projectRoot, profile.profileDir); - // Check if the profile directory exists - const profileDir = path.join(projectRoot, profileConfig.profileDir); - const rulesDir = path.join(projectRoot, profileConfig.rulesDir); - - // A profile is considered installed if either the profile dir or rules dir exists - if (fs.existsSync(profileDir) || fs.existsSync(rulesDir)) { - installedProfiles.push(profileName); + // Check if profile directory exists (skip root directory check) + if (profile.profileDir === '.' || fs.existsSync(profileDir)) { + // Check if any files from the profile's fileMap exist + const rulesDir = path.join(projectRoot, profile.rulesDir); + if (fs.existsSync(rulesDir)) { + const ruleFiles = Object.values(profile.fileMap); + const hasRuleFiles = ruleFiles.some((ruleFile) => + fs.existsSync(path.join(rulesDir, ruleFile)) + ); + if (hasRuleFiles) { + installedProfiles.push(profileName); + } + } + } + } catch (error) { + // Skip profiles that can't be loaded } } @@ -41,32 +65,29 @@ export function getInstalledProfiles(projectRoot) { } /** - * Check if removing the specified profiles would result in no profiles remaining + * Check if removing specified profiles would leave no profiles installed * @param {string} projectRoot - Project root directory * @param {string[]} profilesToRemove - Array of profile names to remove - * @returns {boolean} True if removal would result in no profiles remaining + * @returns {boolean} - True if removal would leave no profiles */ export function wouldRemovalLeaveNoProfiles(projectRoot, profilesToRemove) { const installedProfiles = getInstalledProfiles(projectRoot); + + // If no profiles are currently installed, removal cannot leave no profiles + if (installedProfiles.length === 0) { + return false; + } + const remainingProfiles = installedProfiles.filter( (profile) => !profilesToRemove.includes(profile) ); - - return remainingProfiles.length === 0 && installedProfiles.length > 0; + return remainingProfiles.length === 0; } // ============================================================================= // PROFILE SETUP // ============================================================================= -/** - * Get the display name for a profile - */ -function getProfileDisplayName(name) { - const profile = getRulesProfile(name); - return profile?.displayName || name.charAt(0).toUpperCase() + name.slice(1); -} - // Note: Profile choices are now generated dynamically within runInteractiveProfilesSetup() // to ensure proper alphabetical sorting and pagination configuration @@ -86,26 +107,32 @@ export async function runInteractiveProfilesSetup() { const displayName = getProfileDisplayName(profileName); const profile = getRulesProfile(profileName); - // Determine description based on profile type + // Determine description based on profile capabilities let description; - if (Object.keys(profile.fileMap).length === 0) { - // Simple profiles (Claude, Codex) - specify the target file - const targetFileName = - profileName === 'claude' ? 'CLAUDE.md' : 'AGENTS.md'; - description = `Integration guide (${targetFileName})`; - } else { - // Full profiles with rules - check if they have MCP config - const hasMcpConfig = profile.mcpConfig === true; - if (hasMcpConfig) { - // Special case for Roo to mention agent modes - if (profileName === 'roo') { - description = 'Rule profile, MCP config, and agent modes'; - } else { - description = 'Rule profile and MCP config'; - } + const hasRules = Object.keys(profile.fileMap).length > 0; + const hasMcpConfig = profile.mcpConfig === true; + + if (!profile.includeDefaultRules) { + // Integration guide profiles (claude, codex, gemini) - don't include standard coding rules + if (profileName === 'claude') { + description = 'Integration guide with Task Master slash commands'; + } else if (profileName === 'codex') { + description = 'Comprehensive Task Master integration guide'; + } else if (profileName === 'gemini') { + description = 'Integration guide and MCP config'; } else { - description = 'Rule profile'; + description = 'Integration guide'; } + } else if (hasRules && hasMcpConfig) { + // Full rule profiles with MCP config + if (profileName === 'roo') { + description = 'Rule profile, MCP config, and agent modes'; + } else { + description = 'Rule profile and MCP config'; + } + } else if (hasRules) { + // Rule profiles without MCP config + description = 'Rule profile'; } return { @@ -170,14 +197,13 @@ export async function runInteractiveProfilesSetup() { */ export function generateProfileSummary(profileName, addResult) { const profileConfig = getRulesProfile(profileName); - const isSimpleProfile = Object.keys(profileConfig.fileMap).length === 0; - if (isSimpleProfile) { - // Simple profiles like Claude and Codex only copy AGENTS.md - const targetFileName = profileName === 'claude' ? 'CLAUDE.md' : 'AGENTS.md'; - return `Summary for ${profileName}: Integration guide copied to ${targetFileName}`; + if (!profileConfig.includeDefaultRules) { + // Integration guide profiles (claude, codex, gemini) + return `Summary for ${profileName}: Integration guide installed.`; } else { - return `Summary for ${profileName}: ${addResult.success} rules added, ${addResult.failed} failed.`; + // Rule profiles with coding guidelines + return `Summary for ${profileName}: ${addResult.success} files processed, ${addResult.failed} failed.`; } } @@ -188,9 +214,6 @@ export function generateProfileSummary(profileName, addResult) { * @returns {string} Formatted summary message */ export function generateProfileRemovalSummary(profileName, removeResult) { - const profileConfig = getRulesProfile(profileName); - const isSimpleProfile = Object.keys(profileConfig.fileMap).length === 0; - if (removeResult.skipped) { return `Summary for ${profileName}: Skipped (default or protected files)`; } @@ -199,13 +222,18 @@ export function generateProfileRemovalSummary(profileName, removeResult) { return `Summary for ${profileName}: Failed to remove - ${removeResult.error}`; } - if (isSimpleProfile) { - // Simple profiles like Claude and Codex only have an integration guide - const targetFileName = profileName === 'claude' ? 'CLAUDE.md' : 'AGENTS.md'; - return `Summary for ${profileName}: Integration guide (${targetFileName}) removed`; + const profileConfig = getRulesProfile(profileName); + + if (!profileConfig.includeDefaultRules) { + // Integration guide profiles (claude, codex, gemini) + const baseMessage = `Summary for ${profileName}: Integration guide removed`; + if (removeResult.notice) { + return `${baseMessage} (${removeResult.notice})`; + } + return baseMessage; } else { - // Full profiles have rules directories and potentially MCP configs - const baseMessage = `Summary for ${profileName}: Rules directory removed`; + // Rule profiles with coding guidelines + const baseMessage = `Summary for ${profileName}: Rule profile removed`; if (removeResult.notice) { return `${baseMessage} (${removeResult.notice})`; } @@ -220,7 +248,6 @@ export function generateProfileRemovalSummary(profileName, removeResult) { */ export function categorizeProfileResults(addResults) { const successfulProfiles = []; - const simpleProfiles = []; let totalSuccess = 0; let totalFailed = 0; @@ -228,22 +255,15 @@ export function categorizeProfileResults(addResults) { totalSuccess += r.success; totalFailed += r.failed; - const profileConfig = getRulesProfile(r.profileName); - const isSimpleProfile = Object.keys(profileConfig.fileMap).length === 0; - - if (isSimpleProfile) { - // Simple profiles are successful if they completed without error - simpleProfiles.push(r.profileName); - } else if (r.success > 0) { - // Full profiles are successful if they added rules + // All profiles are considered successful if they completed without major errors + if (r.success > 0 || r.failed === 0) { successfulProfiles.push(r.profileName); } }); return { successfulProfiles, - simpleProfiles, - allSuccessfulProfiles: [...successfulProfiles, ...simpleProfiles], + allSuccessfulProfiles: successfulProfiles, totalSuccess, totalFailed }; diff --git a/src/utils/rule-transformer.js b/src/utils/rule-transformer.js index 2922fa2a..a66c643a 100644 --- a/src/utils/rule-transformer.js +++ b/src/utils/rule-transformer.js @@ -199,97 +199,130 @@ export function convertRuleToProfileRule(sourcePath, targetPath, profile) { * Convert all Cursor rules to profile rules for a specific profile */ export function convertAllRulesToProfileRules(projectRoot, profile) { - // Handle simple profiles (Claude, Codex) that just copy files to root - const isSimpleProfile = Object.keys(profile.fileMap).length === 0; - if (isSimpleProfile) { - // For simple profiles, just call their post-processing hook and return - const __filename = fileURLToPath(import.meta.url); - const __dirname = path.dirname(__filename); - const assetsDir = path.join(__dirname, '..', '..', 'assets'); - - if (typeof profile.onPostConvertRulesProfile === 'function') { - profile.onPostConvertRulesProfile(projectRoot, assetsDir); - } - return { success: 1, failed: 0 }; - } - const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const sourceDir = path.join(__dirname, '..', '..', 'assets', 'rules'); const targetDir = path.join(projectRoot, profile.rulesDir); - - // Ensure target directory exists - if (!fs.existsSync(targetDir)) { - fs.mkdirSync(targetDir, { recursive: true }); - } - - // Setup MCP configuration if enabled - if (profile.mcpConfig !== false) { - setupMCPConfiguration(projectRoot, profile.mcpConfigPath); - } + const assetsDir = path.join(__dirname, '..', '..', 'assets'); let success = 0; let failed = 0; - // Use fileMap to determine which files to copy - const sourceFiles = Object.keys(profile.fileMap); - - for (const sourceFile of sourceFiles) { + // 1. Call onAddRulesProfile first (for pre-processing like copying assets) + if (typeof profile.onAddRulesProfile === 'function') { try { - const sourcePath = path.join(sourceDir, sourceFile); - - // Check if source file exists - if (!fs.existsSync(sourcePath)) { - log( - 'warn', - `[Rule Transformer] Source file not found: ${sourceFile}, skipping` - ); - continue; - } - - const targetFilename = profile.fileMap[sourceFile]; - const targetPath = path.join(targetDir, targetFilename); - - // Ensure target subdirectory exists (for rules like taskmaster/dev_workflow.md) - const targetFileDir = path.dirname(targetPath); - if (!fs.existsSync(targetFileDir)) { - fs.mkdirSync(targetFileDir, { recursive: true }); - } - - // Read source content - let content = fs.readFileSync(sourcePath, 'utf8'); - - // Apply transformations - content = transformRuleContent( - content, - profile.conversionConfig, - profile.globalReplacements - ); - - // Write to target - fs.writeFileSync(targetPath, content, 'utf8'); - success++; - + profile.onAddRulesProfile(projectRoot, assetsDir); log( 'debug', - `[Rule Transformer] Converted ${sourceFile} -> ${targetFilename} for ${profile.profileName}` + `[Rule Transformer] Called onAddRulesProfile for ${profile.profileName}` ); } catch (error) { - failed++; log( 'error', - `[Rule Transformer] Failed to convert ${sourceFile} for ${profile.profileName}: ${error.message}` + `[Rule Transformer] onAddRulesProfile failed for ${profile.profileName}: ${error.message}` + ); + failed++; + } + } + + // 2. Handle fileMap-based rule conversion (if any) + const sourceFiles = Object.keys(profile.fileMap); + if (sourceFiles.length > 0) { + // Only create rules directory if we have files to copy + if (!fs.existsSync(targetDir)) { + fs.mkdirSync(targetDir, { recursive: true }); + } + + for (const sourceFile of sourceFiles) { + // Determine if this is an asset file (not a rule file) + const isAssetFile = !sourceFile.startsWith('rules/'); + + try { + // Use explicit path from fileMap - assets/ is the base directory + const sourcePath = path.join(assetsDir, sourceFile); + + // Check if source file exists + if (!fs.existsSync(sourcePath)) { + log( + 'warn', + `[Rule Transformer] Source file not found: ${sourcePath}, skipping` + ); + continue; + } + + const targetFilename = profile.fileMap[sourceFile]; + const targetPath = path.join(targetDir, targetFilename); + + // Ensure target subdirectory exists (for rules like taskmaster/dev_workflow.md) + const targetFileDir = path.dirname(targetPath); + if (!fs.existsSync(targetFileDir)) { + fs.mkdirSync(targetFileDir, { recursive: true }); + } + + // Read source content + let content = fs.readFileSync(sourcePath, 'utf8'); + + // Apply transformations (only if this is a rule file, not an asset file) + if (!isAssetFile) { + content = transformRuleContent( + content, + profile.conversionConfig, + profile.globalReplacements + ); + } + + // Write to target + fs.writeFileSync(targetPath, content, 'utf8'); + success++; + + log( + 'debug', + `[Rule Transformer] ${isAssetFile ? 'Copied' : 'Converted'} ${sourceFile} -> ${targetFilename} for ${profile.profileName}` + ); + } catch (error) { + failed++; + log( + 'error', + `[Rule Transformer] Failed to ${isAssetFile ? 'copy' : 'convert'} ${sourceFile} for ${profile.profileName}: ${error.message}` + ); + } + } + } + + // 3. Setup MCP configuration (if enabled) + if (profile.mcpConfig !== false) { + try { + setupMCPConfiguration(projectRoot, profile.mcpConfigPath); + log( + 'debug', + `[Rule Transformer] Setup MCP configuration for ${profile.profileName}` + ); + } catch (error) { + log( + 'error', + `[Rule Transformer] MCP setup failed for ${profile.profileName}: ${error.message}` ); } } - // Call post-processing hook if defined (e.g., for Roo's rules-*mode* folders) + // 4. Call post-conversion hook (for finalization) if (typeof profile.onPostConvertRulesProfile === 'function') { - const assetsDir = path.join(__dirname, '..', '..', 'assets'); - profile.onPostConvertRulesProfile(projectRoot, assetsDir); + try { + profile.onPostConvertRulesProfile(projectRoot, assetsDir); + log( + 'debug', + `[Rule Transformer] Called onPostConvertRulesProfile for ${profile.profileName}` + ); + } catch (error) { + log( + 'error', + `[Rule Transformer] onPostConvertRulesProfile failed for ${profile.profileName}: ${error.message}` + ); + } } - return { success, failed }; + // Ensure we return at least 1 success for profiles that only use lifecycle functions + return { success: Math.max(success, 1), failed }; } /** @@ -314,176 +347,147 @@ export function removeProfileRules(projectRoot, profile) { }; try { - // Handle simple profiles (Claude, Codex) that just copy files to root - const isSimpleProfile = Object.keys(profile.fileMap).length === 0; - - if (isSimpleProfile) { - // For simple profiles, just call their removal hook and return - if (typeof profile.onRemoveRulesProfile === 'function') { + // 1. Call onRemoveRulesProfile first (for custom cleanup like removing assets) + if (typeof profile.onRemoveRulesProfile === 'function') { + try { profile.onRemoveRulesProfile(projectRoot); + log( + 'debug', + `[Rule Transformer] Called onRemoveRulesProfile for ${profile.profileName}` + ); + } catch (error) { + log( + 'error', + `[Rule Transformer] onRemoveRulesProfile failed for ${profile.profileName}: ${error.message}` + ); } - result.success = true; - log( - 'debug', - `[Rule Transformer] Successfully removed ${profile.profileName} files from ${projectRoot}` - ); - return result; } - // Check if profile directory exists at all (for full profiles) - if (!fs.existsSync(profileDir)) { - result.success = true; - result.skipped = true; - log( - 'debug', - `[Rule Transformer] Profile directory does not exist: ${profileDir}` - ); - return result; - } + // 2. Remove fileMap-based files (if any) + const sourceFiles = Object.keys(profile.fileMap); + if (sourceFiles.length > 0) { + // Check if profile directory exists at all (for full profiles) + if (!fs.existsSync(profileDir)) { + result.success = true; + result.skipped = true; + log( + 'debug', + `[Rule Transformer] Profile directory does not exist: ${profileDir}` + ); + return result; + } - // 1. Remove only Task Master specific files from the rules directory - let hasOtherRulesFiles = false; - if (fs.existsSync(targetDir)) { - const taskmasterFiles = Object.values(profile.fileMap); - const removedFiles = []; + let hasOtherRulesFiles = false; - // Helper function to recursively check and remove Task Master files - function processDirectory(dirPath, relativePath = '') { - const items = fs.readdirSync(dirPath); + if (fs.existsSync(targetDir)) { + // Get list of files we're responsible for + const taskMasterFiles = sourceFiles.map( + (sourceFile) => profile.fileMap[sourceFile] + ); - for (const item of items) { - const itemPath = path.join(dirPath, item); - const relativeItemPath = relativePath - ? path.join(relativePath, item) - : item; - const stat = fs.statSync(itemPath); + // Get all files in the rules directory + const allFiles = fs.readdirSync(targetDir, { recursive: true }); + const allFilePaths = allFiles + .filter((file) => { + const fullPath = path.join(targetDir, file); + return fs.statSync(fullPath).isFile(); + }) + .map((file) => file.toString()); // Ensure it's a string - if (stat.isDirectory()) { - // Recursively process subdirectory - processDirectory(itemPath, relativeItemPath); - - // Check if directory is empty after processing and remove if so + // Remove only Task Master files + for (const taskMasterFile of taskMasterFiles) { + const filePath = path.join(targetDir, taskMasterFile); + if (fs.existsSync(filePath)) { try { - const remainingItems = fs.readdirSync(itemPath); - if (remainingItems.length === 0) { - fs.rmSync(itemPath, { recursive: true, force: true }); - log( - 'debug', - `[Rule Transformer] Removed empty directory: ${relativeItemPath}` - ); - } - } catch (error) { - // Directory might have been removed already, ignore - } - } else if (stat.isFile()) { - if (taskmasterFiles.includes(relativeItemPath)) { - // This is a Task Master file, remove it - fs.rmSync(itemPath, { force: true }); - removedFiles.push(relativeItemPath); + fs.rmSync(filePath, { force: true }); + result.filesRemoved.push(taskMasterFile); log( 'debug', - `[Rule Transformer] Removed Task Master file: ${relativeItemPath}` + `[Rule Transformer] Removed Task Master file: ${taskMasterFile}` ); - } else { - // This is not a Task Master file, leave it - hasOtherRulesFiles = true; + } catch (error) { log( - 'debug', - `[Rule Transformer] Preserved existing file: ${relativeItemPath}` + 'error', + `[Rule Transformer] Failed to remove ${taskMasterFile}: ${error.message}` ); } } } - } - // Process the rules directory recursively - processDirectory(targetDir); - - result.filesRemoved = removedFiles; - - // Only remove the rules directory if it's empty after removing Task Master files - const remainingFiles = fs.readdirSync(targetDir); - if (remainingFiles.length === 0) { - fs.rmSync(targetDir, { recursive: true, force: true }); - log( - 'debug', - `[Rule Transformer] Removed empty rules directory: ${targetDir}` + // Check for other (non-Task Master) files + const remainingFiles = allFilePaths.filter( + (file) => !taskMasterFiles.includes(file) ); - } else if (hasOtherRulesFiles) { - result.notice = `Preserved ${remainingFiles.length} existing rule files in ${profile.rulesDir}`; - log('info', `[Rule Transformer] ${result.notice}`); - } - } - // 2. Handle MCP configuration - only remove Task Master, preserve other servers - if (profile.mcpConfig !== false) { - result.mcpResult = removeTaskMasterMCPConfiguration( - projectRoot, - profile.mcpConfigPath - ); - if (result.mcpResult.hasOtherServers) { - if (!result.notice) { - result.notice = 'Preserved other MCP server configurations'; - } else { - result.notice += '; preserved other MCP server configurations'; + hasOtherRulesFiles = remainingFiles.length > 0; + + // Remove empty directories or note preserved files + if (remainingFiles.length === 0) { + fs.rmSync(targetDir, { recursive: true, force: true }); + log( + 'debug', + `[Rule Transformer] Removed empty rules directory: ${targetDir}` + ); + } else if (hasOtherRulesFiles) { + result.notice = `Preserved ${remainingFiles.length} existing rule files in ${profile.rulesDir}`; + log('info', `[Rule Transformer] ${result.notice}`); } } } - // 3. Call removal hook if defined (e.g., Roo's custom cleanup) - if (typeof profile.onRemoveRulesProfile === 'function') { - profile.onRemoveRulesProfile(projectRoot); - } - - // 4. Only remove profile directory if: - // - It's completely empty after all operations, AND - // - All rules removed were Task Master rules (no existing rules preserved), AND - // - MCP config was completely deleted (not just Task Master removed), AND - // - No other files or folders exist in the profile directory - if (fs.existsSync(profileDir)) { - const remaining = fs.readdirSync(profileDir); - const allRulesWereTaskMaster = !hasOtherRulesFiles; - const mcpConfigCompletelyDeleted = result.mcpResult?.deleted === true; - - // Check if there are any other files or folders beyond what we expect - const hasOtherFilesOrFolders = remaining.length > 0; - - if ( - remaining.length === 0 && - allRulesWereTaskMaster && - (profile.mcpConfig === false || mcpConfigCompletelyDeleted) && - !hasOtherFilesOrFolders - ) { - fs.rmSync(profileDir, { recursive: true, force: true }); - result.profileDirRemoved = true; + // 3. Handle MCP configuration - only remove Task Master, preserve other servers + if (profile.mcpConfig !== false) { + try { + result.mcpResult = removeTaskMasterMCPConfiguration( + projectRoot, + profile.mcpConfigPath + ); + if (result.mcpResult.hasOtherServers) { + if (!result.notice) { + result.notice = 'Preserved other MCP server configurations'; + } else { + result.notice += '; preserved other MCP server configurations'; + } + } log( 'debug', - `[Rule Transformer] Removed profile directory: ${profileDir} (completely empty, all rules were Task Master rules, and MCP config was completely removed)` + `[Rule Transformer] Processed MCP configuration for ${profile.profileName}` ); - } else { - // Determine what was preserved and why - const preservationReasons = []; - if (hasOtherFilesOrFolders) { - preservationReasons.push( - `${remaining.length} existing files/folders` + } catch (error) { + log( + 'error', + `[Rule Transformer] MCP cleanup failed for ${profile.profileName}: ${error.message}` + ); + } + } + + // 4. Check if we should remove the entire profile directory + if (fs.existsSync(profileDir)) { + const remainingContents = fs.readdirSync(profileDir); + if (remainingContents.length === 0 && profile.profileDir !== '.') { + // Only remove profile directory if it's empty and not root directory + try { + fs.rmSync(profileDir, { recursive: true, force: true }); + result.profileDirRemoved = true; + log( + 'debug', + `[Rule Transformer] Removed empty profile directory: ${profileDir}` + ); + } catch (error) { + log( + 'error', + `[Rule Transformer] Failed to remove profile directory ${profileDir}: ${error.message}` ); } - if (hasOtherRulesFiles) { - preservationReasons.push('existing rule files'); - } - if (result.mcpResult?.hasOtherServers) { - preservationReasons.push('other MCP server configurations'); - } - - const preservationMessage = `Preserved ${preservationReasons.join(', ')} in ${profile.profileDir}`; - + } else if (remainingContents.length > 0) { + // Profile directory has remaining files/folders, add notice + const preservedNotice = `Preserved ${remainingContents.length} existing files/folders in ${profile.profileDir}`; if (!result.notice) { - result.notice = preservationMessage; - } else if (!result.notice.includes('Preserved')) { - result.notice += `; ${preservationMessage.toLowerCase()}`; + result.notice = preservedNotice; + } else { + result.notice += `; ${preservedNotice.toLowerCase()}`; } - - log('info', `[Rule Transformer] ${preservationMessage}`); + log('info', `[Rule Transformer] ${preservedNotice}`); } } diff --git a/tests/integration/profiles/claude-init-functionality.test.js b/tests/integration/profiles/claude-init-functionality.test.js index 1a765bfe..b597da8c 100644 --- a/tests/integration/profiles/claude-init-functionality.test.js +++ b/tests/integration/profiles/claude-init-functionality.test.js @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { claudeProfile } from '../../../src/profiles/claude.js'; describe('Claude Profile Initialization Functionality', () => { let claudeProfileContent; @@ -14,23 +15,25 @@ describe('Claude Profile Initialization Functionality', () => { claudeProfileContent = fs.readFileSync(claudeJsPath, 'utf8'); }); - test('claude.js is a simple profile with correct configuration', () => { - expect(claudeProfileContent).toContain("profileName: 'claude'"); + test('claude.js has correct asset-only profile configuration', () => { + // Check for explicit, non-default values in the source file + expect(claudeProfileContent).toContain("name: 'claude'"); expect(claudeProfileContent).toContain("displayName: 'Claude Code'"); - expect(claudeProfileContent).toContain("profileDir: '.'"); - expect(claudeProfileContent).toContain("rulesDir: '.'"); - }); + expect(claudeProfileContent).toContain("profileDir: '.'"); // non-default + expect(claudeProfileContent).toContain("rulesDir: '.'"); // non-default + expect(claudeProfileContent).toContain('mcpConfig: false'); // non-default + expect(claudeProfileContent).toContain('includeDefaultRules: false'); // non-default + expect(claudeProfileContent).toContain("'AGENTS.md': 'CLAUDE.md'"); - test('claude.js has no MCP configuration', () => { - expect(claudeProfileContent).toContain('mcpConfig: false'); - expect(claudeProfileContent).toContain('mcpConfigName: null'); - expect(claudeProfileContent).toContain('mcpConfigPath: null'); - }); - - test('claude.js has empty file map (simple profile)', () => { - expect(claudeProfileContent).toContain('fileMap: {}'); - expect(claudeProfileContent).toContain('conversionConfig: {}'); - expect(claudeProfileContent).toContain('globalReplacements: []'); + // Check the final computed properties on the profile object + expect(claudeProfile.profileName).toBe('claude'); + expect(claudeProfile.displayName).toBe('Claude Code'); + expect(claudeProfile.profileDir).toBe('.'); + expect(claudeProfile.rulesDir).toBe('.'); + expect(claudeProfile.mcpConfig).toBe(false); + expect(claudeProfile.mcpConfigName).toBe(null); // computed + expect(claudeProfile.includeDefaultRules).toBe(false); + expect(claudeProfile.fileMap['AGENTS.md']).toBe('CLAUDE.md'); }); test('claude.js has lifecycle functions for file management', () => { @@ -41,13 +44,12 @@ describe('Claude Profile Initialization Functionality', () => { ); }); - test('claude.js copies AGENTS.md to CLAUDE.md', () => { - expect(claudeProfileContent).toContain("'AGENTS.md'"); - expect(claudeProfileContent).toContain("'CLAUDE.md'"); - expect(claudeProfileContent).toContain('copyFileSync'); + test('claude.js handles .claude directory in lifecycle functions', () => { + expect(claudeProfileContent).toContain('.claude'); + expect(claudeProfileContent).toContain('copyRecursiveSync'); }); - test('claude.js has proper error handling', () => { + test('claude.js has proper error handling in lifecycle functions', () => { expect(claudeProfileContent).toContain('try {'); expect(claudeProfileContent).toContain('} catch (err) {'); expect(claudeProfileContent).toContain("log('error'"); diff --git a/tests/integration/profiles/cline-init-functionality.test.js b/tests/integration/profiles/cline-init-functionality.test.js index af1d90cc..822b045b 100644 --- a/tests/integration/profiles/cline-init-functionality.test.js +++ b/tests/integration/profiles/cline-init-functionality.test.js @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { clineProfile } from '../../../src/profiles/cline.js'; describe('Cline Profile Initialization Functionality', () => { let clineProfileContent; @@ -10,39 +11,48 @@ describe('Cline Profile Initialization Functionality', () => { }); test('cline.js uses factory pattern with correct configuration', () => { + // Check for explicit, non-default values in the source file expect(clineProfileContent).toContain("name: 'cline'"); expect(clineProfileContent).toContain("displayName: 'Cline'"); - expect(clineProfileContent).toContain("rulesDir: '.clinerules'"); - expect(clineProfileContent).toContain("profileDir: '.clinerules'"); + expect(clineProfileContent).toContain("profileDir: '.clinerules'"); // non-default + expect(clineProfileContent).toContain("rulesDir: '.clinerules'"); // non-default + expect(clineProfileContent).toContain('mcpConfig: false'); // non-default + + // Check the final computed properties on the profile object + expect(clineProfile.profileName).toBe('cline'); + expect(clineProfile.displayName).toBe('Cline'); + expect(clineProfile.profileDir).toBe('.clinerules'); + expect(clineProfile.rulesDir).toBe('.clinerules'); + expect(clineProfile.mcpConfig).toBe(false); + expect(clineProfile.mcpConfigName).toBe(null); }); test('cline.js configures .mdc to .md extension mapping', () => { - expect(clineProfileContent).toContain("fileExtension: '.mdc'"); - expect(clineProfileContent).toContain("targetExtension: '.md'"); - }); - - test('cline.js uses standard tool mappings', () => { - expect(clineProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD'); - // Should contain comment about standard tool names - expect(clineProfileContent).toContain('standard tool names'); - }); - - test('cline.js contains correct URL configuration', () => { - expect(clineProfileContent).toContain("url: 'cline.bot'"); - expect(clineProfileContent).toContain("docsUrl: 'docs.cline.bot'"); - }); - - test('cline.js has MCP configuration disabled', () => { - expect(clineProfileContent).toContain('mcpConfig: false'); - expect(clineProfileContent).toContain( - "mcpConfigName: 'cline_mcp_settings.json'" + // Check that the profile object has the correct file mapping behavior (cline converts to .md) + expect(clineProfile.fileMap['rules/cursor_rules.mdc']).toBe( + 'cline_rules.md' ); }); + test('cline.js uses standard tool mappings', () => { + // Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD) + // This verifies the architectural pattern: no custom toolMappings = standard tool names + expect(clineProfileContent).not.toContain('toolMappings:'); + expect(clineProfileContent).not.toContain('apply_diff'); + expect(clineProfileContent).not.toContain('search_files'); + + // Verify the result: default mappings means tools keep their original names + expect(clineProfile.conversionConfig.toolNames.edit_file).toBe('edit_file'); + expect(clineProfile.conversionConfig.toolNames.search).toBe('search'); + }); + test('cline.js has custom file mapping for cursor_rules.mdc', () => { - expect(clineProfileContent).toContain('customFileMap:'); - expect(clineProfileContent).toContain( - "'cursor_rules.mdc': 'cline_rules.md'" + // Check actual behavior - cline gets default rule files + expect(Object.keys(clineProfile.fileMap)).toContain( + 'rules/cursor_rules.mdc' + ); + expect(clineProfile.fileMap['rules/cursor_rules.mdc']).toBe( + 'cline_rules.md' ); }); diff --git a/tests/integration/profiles/codex-init-functionality.test.js b/tests/integration/profiles/codex-init-functionality.test.js index 55c11321..ce1a6487 100644 --- a/tests/integration/profiles/codex-init-functionality.test.js +++ b/tests/integration/profiles/codex-init-functionality.test.js @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { codexProfile } from '../../../src/profiles/codex.js'; describe('Codex Profile Initialization Functionality', () => { let codexProfileContent; @@ -9,46 +10,41 @@ describe('Codex Profile Initialization Functionality', () => { codexProfileContent = fs.readFileSync(codexJsPath, 'utf8'); }); - test('codex.js is a simple profile with correct configuration', () => { - expect(codexProfileContent).toContain("profileName: 'codex'"); + test('codex.js has correct asset-only profile configuration', () => { + // Check for explicit, non-default values in the source file + expect(codexProfileContent).toContain("name: 'codex'"); expect(codexProfileContent).toContain("displayName: 'Codex'"); - expect(codexProfileContent).toContain("profileDir: '.'"); - expect(codexProfileContent).toContain("rulesDir: '.'"); + expect(codexProfileContent).toContain("profileDir: '.'"); // non-default + expect(codexProfileContent).toContain("rulesDir: '.'"); // non-default + expect(codexProfileContent).toContain('mcpConfig: false'); // non-default + expect(codexProfileContent).toContain('includeDefaultRules: false'); // non-default + expect(codexProfileContent).toContain("'AGENTS.md': 'AGENTS.md'"); + + // Check the final computed properties on the profile object + expect(codexProfile.profileName).toBe('codex'); + expect(codexProfile.displayName).toBe('Codex'); + expect(codexProfile.profileDir).toBe('.'); + expect(codexProfile.rulesDir).toBe('.'); + expect(codexProfile.mcpConfig).toBe(false); + expect(codexProfile.mcpConfigName).toBe(null); // computed + expect(codexProfile.includeDefaultRules).toBe(false); + expect(codexProfile.fileMap['AGENTS.md']).toBe('AGENTS.md'); }); - test('codex.js has no MCP configuration', () => { - expect(codexProfileContent).toContain('mcpConfig: false'); - expect(codexProfileContent).toContain('mcpConfigName: null'); - expect(codexProfileContent).toContain('mcpConfigPath: null'); + test('codex.js has no lifecycle functions', () => { + // Codex has been simplified - no lifecycle functions + expect(codexProfileContent).not.toContain('function onAddRulesProfile'); + expect(codexProfileContent).not.toContain('function onRemoveRulesProfile'); + expect(codexProfileContent).not.toContain( + 'function onPostConvertRulesProfile' + ); + expect(codexProfileContent).not.toContain('log('); }); - test('codex.js has empty file map (simple profile)', () => { - expect(codexProfileContent).toContain('fileMap: {}'); - expect(codexProfileContent).toContain('conversionConfig: {}'); - expect(codexProfileContent).toContain('globalReplacements: []'); - }); - - test('codex.js has lifecycle functions for file management', () => { - expect(codexProfileContent).toContain('function onAddRulesProfile'); - expect(codexProfileContent).toContain('function onRemoveRulesProfile'); - expect(codexProfileContent).toContain('function onPostConvertRulesProfile'); - }); - - test('codex.js copies AGENTS.md to AGENTS.md (same filename)', () => { - expect(codexProfileContent).toContain("'AGENTS.md'"); - expect(codexProfileContent).toContain('copyFileSync'); - // Should copy to the same filename (AGENTS.md) - expect(codexProfileContent).toMatch(/destFile.*AGENTS\.md/); - }); - - test('codex.js has proper error handling', () => { - expect(codexProfileContent).toContain('try {'); - expect(codexProfileContent).toContain('} catch (err) {'); - expect(codexProfileContent).toContain("log('error'"); - }); - - test('codex.js removes AGENTS.md on profile removal', () => { - expect(codexProfileContent).toContain('rmSync'); - expect(codexProfileContent).toContain('force: true'); + test('codex.js has minimal implementation', () => { + // Should just use createProfile factory + expect(codexProfileContent).toContain('createProfile({'); + expect(codexProfileContent).toContain("name: 'codex'"); + expect(codexProfileContent).toContain("'AGENTS.md': 'AGENTS.md'"); }); }); diff --git a/tests/integration/profiles/cursor-init-functionality.test.js b/tests/integration/profiles/cursor-init-functionality.test.js index f6045c40..a07ea38f 100644 --- a/tests/integration/profiles/cursor-init-functionality.test.js +++ b/tests/integration/profiles/cursor-init-functionality.test.js @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { cursorProfile } from '../../../src/profiles/cursor.js'; describe('Cursor Profile Initialization Functionality', () => { let cursorProfileContent; @@ -15,30 +16,42 @@ describe('Cursor Profile Initialization Functionality', () => { }); test('cursor.js uses factory pattern with correct configuration', () => { + // Check for explicit, non-default values in the source file expect(cursorProfileContent).toContain("name: 'cursor'"); expect(cursorProfileContent).toContain("displayName: 'Cursor'"); - expect(cursorProfileContent).toContain("rulesDir: '.cursor/rules'"); - expect(cursorProfileContent).toContain("profileDir: '.cursor'"); + expect(cursorProfileContent).toContain("url: 'cursor.so'"); + expect(cursorProfileContent).toContain("docsUrl: 'docs.cursor.com'"); + expect(cursorProfileContent).toContain("targetExtension: '.mdc'"); // non-default + + // Check the final computed properties on the profile object + expect(cursorProfile.profileName).toBe('cursor'); + expect(cursorProfile.displayName).toBe('Cursor'); + expect(cursorProfile.profileDir).toBe('.cursor'); // default + expect(cursorProfile.rulesDir).toBe('.cursor/rules'); // default + expect(cursorProfile.mcpConfig).toBe(true); // default + expect(cursorProfile.mcpConfigName).toBe('mcp.json'); // default }); test('cursor.js preserves .mdc extension in both input and output', () => { - expect(cursorProfileContent).toContain("fileExtension: '.mdc'"); - expect(cursorProfileContent).toContain("targetExtension: '.mdc'"); - // Should preserve cursor_rules.mdc filename - expect(cursorProfileContent).toContain( - "'cursor_rules.mdc': 'cursor_rules.mdc'" + // Check that the profile object has the correct file mapping behavior (cursor keeps .mdc) + expect(cursorProfile.fileMap['rules/cursor_rules.mdc']).toBe( + 'cursor_rules.mdc' ); + // Also check that targetExtension is explicitly set in the file + expect(cursorProfileContent).toContain("targetExtension: '.mdc'"); }); test('cursor.js uses standard tool mappings (no tool renaming)', () => { - expect(cursorProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD'); - // Should not contain custom tool mappings since cursor keeps original names - expect(cursorProfileContent).not.toContain('edit_file'); + // Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD) + // This verifies the architectural pattern: no custom toolMappings = standard tool names + expect(cursorProfileContent).not.toContain('toolMappings:'); expect(cursorProfileContent).not.toContain('apply_diff'); - }); + expect(cursorProfileContent).not.toContain('search_files'); - test('cursor.js contains correct URL configuration', () => { - expect(cursorProfileContent).toContain("url: 'cursor.so'"); - expect(cursorProfileContent).toContain("docsUrl: 'docs.cursor.com'"); + // Verify the result: default mappings means tools keep their original names + expect(cursorProfile.conversionConfig.toolNames.edit_file).toBe( + 'edit_file' + ); + expect(cursorProfile.conversionConfig.toolNames.search).toBe('search'); }); }); diff --git a/tests/integration/profiles/gemini-init-functionality.test.js b/tests/integration/profiles/gemini-init-functionality.test.js new file mode 100644 index 00000000..6b7b9e7f --- /dev/null +++ b/tests/integration/profiles/gemini-init-functionality.test.js @@ -0,0 +1,72 @@ +import fs from 'fs'; +import path from 'path'; +import { geminiProfile } from '../../../src/profiles/gemini.js'; + +describe('Gemini Profile Initialization Functionality', () => { + let geminiProfileContent; + + beforeAll(() => { + const geminiJsPath = path.join( + process.cwd(), + 'src', + 'profiles', + 'gemini.js' + ); + geminiProfileContent = fs.readFileSync(geminiJsPath, 'utf8'); + }); + + test('gemini.js has correct profile configuration', () => { + // Check for explicit, non-default values in the source file + expect(geminiProfileContent).toContain("name: 'gemini'"); + expect(geminiProfileContent).toContain("displayName: 'Gemini'"); + expect(geminiProfileContent).toContain("url: 'codeassist.google'"); + expect(geminiProfileContent).toContain( + "docsUrl: 'github.com/google-gemini/gemini-cli'" + ); + expect(geminiProfileContent).toContain("profileDir: '.gemini'"); + expect(geminiProfileContent).toContain("rulesDir: '.'"); // non-default + expect(geminiProfileContent).toContain("mcpConfigName: 'settings.json'"); // non-default + expect(geminiProfileContent).toContain('includeDefaultRules: false'); // non-default + expect(geminiProfileContent).toContain("'AGENTS.md': 'GEMINI.md'"); + + // Check the final computed properties on the profile object + expect(geminiProfile.profileName).toBe('gemini'); + expect(geminiProfile.displayName).toBe('Gemini'); + expect(geminiProfile.profileDir).toBe('.gemini'); + expect(geminiProfile.rulesDir).toBe('.'); + expect(geminiProfile.mcpConfig).toBe(true); // computed from mcpConfigName + expect(geminiProfile.mcpConfigName).toBe('settings.json'); + expect(geminiProfile.mcpConfigPath).toBe('.gemini/settings.json'); // computed + expect(geminiProfile.includeDefaultRules).toBe(false); + expect(geminiProfile.fileMap['AGENTS.md']).toBe('GEMINI.md'); + }); + + test('gemini.js has no lifecycle functions', () => { + // Gemini profile should not have any lifecycle functions + expect(geminiProfileContent).not.toContain('function onAddRulesProfile'); + expect(geminiProfileContent).not.toContain('function onRemoveRulesProfile'); + expect(geminiProfileContent).not.toContain( + 'function onPostConvertRulesProfile' + ); + expect(geminiProfileContent).not.toContain('onAddRulesProfile:'); + expect(geminiProfileContent).not.toContain('onRemoveRulesProfile:'); + expect(geminiProfileContent).not.toContain('onPostConvertRulesProfile:'); + }); + + test('gemini.js uses custom MCP config name', () => { + // Gemini uses settings.json instead of mcp.json + expect(geminiProfileContent).toContain("mcpConfigName: 'settings.json'"); + // Should not contain mcp.json as a config value (comments are OK) + expect(geminiProfileContent).not.toMatch( + /mcpConfigName:\s*['"]mcp\.json['"]/ + ); + }); + + test('gemini.js has minimal implementation', () => { + // Verify the profile is minimal (no extra functions or logic) + const lines = geminiProfileContent.split('\n'); + const nonEmptyLines = lines.filter((line) => line.trim().length > 0); + // Should be around 16 lines (import, export, and profile definition) + expect(nonEmptyLines.length).toBeLessThan(20); + }); +}); diff --git a/tests/integration/profiles/roo-init-functionality.test.js b/tests/integration/profiles/roo-init-functionality.test.js index 5fef9791..d26d75ce 100644 --- a/tests/integration/profiles/roo-init-functionality.test.js +++ b/tests/integration/profiles/roo-init-functionality.test.js @@ -1,6 +1,8 @@ import { jest } from '@jest/globals'; import fs from 'fs'; import path from 'path'; +import { rooProfile } from '../../../src/profiles/roo.js'; +import { COMMON_TOOL_MAPPINGS } from '../../../src/profiles/base-profile.js'; describe('Roo Profile Initialization Functionality', () => { let rooProfileContent; @@ -11,6 +13,33 @@ describe('Roo Profile Initialization Functionality', () => { rooProfileContent = fs.readFileSync(rooJsPath, 'utf8'); }); + test('roo.js uses factory pattern with correct configuration', () => { + // Check for explicit, non-default values in the source file + expect(rooProfileContent).toContain("name: 'roo'"); + expect(rooProfileContent).toContain("displayName: 'Roo Code'"); + expect(rooProfileContent).toContain( + 'toolMappings: COMMON_TOOL_MAPPINGS.ROO_STYLE' + ); + + // Check the final computed properties on the profile object + expect(rooProfile.profileName).toBe('roo'); + expect(rooProfile.displayName).toBe('Roo Code'); + expect(rooProfile.profileDir).toBe('.roo'); // default + expect(rooProfile.rulesDir).toBe('.roo/rules'); // default + expect(rooProfile.mcpConfig).toBe(true); // default + }); + + test('roo.js uses custom ROO_STYLE tool mappings', () => { + // Check that the profile uses the correct, non-standard tool mappings + expect(rooProfileContent).toContain( + 'toolMappings: COMMON_TOOL_MAPPINGS.ROO_STYLE' + ); + + // Verify the result: roo uses custom tool names + expect(rooProfile.conversionConfig.toolNames.edit_file).toBe('apply_diff'); + expect(rooProfile.conversionConfig.toolNames.search).toBe('search_files'); + }); + test('roo.js profile ensures Roo directory structure via onAddRulesProfile', () => { // Check if onAddRulesProfile function exists expect(rooProfileContent).toContain( diff --git a/tests/integration/profiles/trae-init-functionality.test.js b/tests/integration/profiles/trae-init-functionality.test.js index 74badfb2..8cbb2cb1 100644 --- a/tests/integration/profiles/trae-init-functionality.test.js +++ b/tests/integration/profiles/trae-init-functionality.test.js @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { traeProfile } from '../../../src/profiles/trae.js'; describe('Trae Profile Initialization Functionality', () => { let traeProfileContent; @@ -10,32 +11,36 @@ describe('Trae Profile Initialization Functionality', () => { }); test('trae.js uses factory pattern with correct configuration', () => { + // Check for explicit, non-default values in the source file expect(traeProfileContent).toContain("name: 'trae'"); expect(traeProfileContent).toContain("displayName: 'Trae'"); - expect(traeProfileContent).toContain("rulesDir: '.trae/rules'"); - expect(traeProfileContent).toContain("profileDir: '.trae'"); + expect(traeProfileContent).toContain("url: 'trae.ai'"); + expect(traeProfileContent).toContain("docsUrl: 'docs.trae.ai'"); + expect(traeProfileContent).toContain('mcpConfig: false'); + + // Check the final computed properties on the profile object + expect(traeProfile.profileName).toBe('trae'); + expect(traeProfile.displayName).toBe('Trae'); + expect(traeProfile.profileDir).toBe('.trae'); // default + expect(traeProfile.rulesDir).toBe('.trae/rules'); // default + expect(traeProfile.mcpConfig).toBe(false); // non-default + expect(traeProfile.mcpConfigName).toBe(null); // computed from mcpConfig }); test('trae.js configures .mdc to .md extension mapping', () => { - expect(traeProfileContent).toContain("fileExtension: '.mdc'"); - expect(traeProfileContent).toContain("targetExtension: '.md'"); + // Check that the profile object has the correct file mapping behavior (trae converts to .md) + expect(traeProfile.fileMap['rules/cursor_rules.mdc']).toBe('trae_rules.md'); }); test('trae.js uses standard tool mappings', () => { - expect(traeProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD'); - // Should contain comment about standard tool names - expect(traeProfileContent).toContain('standard tool names'); - }); + // Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD) + // This verifies the architectural pattern: no custom toolMappings = standard tool names + expect(traeProfileContent).not.toContain('toolMappings:'); + expect(traeProfileContent).not.toContain('apply_diff'); + expect(traeProfileContent).not.toContain('search_files'); - test('trae.js contains correct URL configuration', () => { - expect(traeProfileContent).toContain("url: 'trae.ai'"); - expect(traeProfileContent).toContain("docsUrl: 'docs.trae.ai'"); - }); - - test('trae.js has MCP configuration disabled', () => { - expect(traeProfileContent).toContain('mcpConfig: false'); - expect(traeProfileContent).toContain( - "mcpConfigName: 'trae_mcp_settings.json'" - ); + // Verify the result: default mappings means tools keep their original names + expect(traeProfile.conversionConfig.toolNames.edit_file).toBe('edit_file'); + expect(traeProfile.conversionConfig.toolNames.search).toBe('search'); }); }); diff --git a/tests/integration/profiles/vscode-init-functionality.test.js b/tests/integration/profiles/vscode-init-functionality.test.js new file mode 100644 index 00000000..794b673a --- /dev/null +++ b/tests/integration/profiles/vscode-init-functionality.test.js @@ -0,0 +1,58 @@ +import fs from 'fs'; +import path from 'path'; +import { vscodeProfile } from '../../../src/profiles/vscode.js'; + +describe('VSCode Profile Initialization Functionality', () => { + let vscodeProfileContent; + + beforeAll(() => { + const vscodeJsPath = path.join( + process.cwd(), + 'src', + 'profiles', + 'vscode.js' + ); + vscodeProfileContent = fs.readFileSync(vscodeJsPath, 'utf8'); + }); + + test('vscode.js uses factory pattern with correct configuration', () => { + // Check for explicit, non-default values in the source file + expect(vscodeProfileContent).toContain("name: 'vscode'"); + expect(vscodeProfileContent).toContain("displayName: 'VS Code'"); + expect(vscodeProfileContent).toContain("url: 'code.visualstudio.com'"); + expect(vscodeProfileContent).toContain( + "docsUrl: 'code.visualstudio.com/docs'" + ); + expect(vscodeProfileContent).toContain("rulesDir: '.github/instructions'"); // non-default + expect(vscodeProfileContent).toContain('customReplacements'); // non-default + + // Check the final computed properties on the profile object + expect(vscodeProfile.profileName).toBe('vscode'); + expect(vscodeProfile.displayName).toBe('VS Code'); + expect(vscodeProfile.profileDir).toBe('.vscode'); // default + expect(vscodeProfile.rulesDir).toBe('.github/instructions'); // non-default + expect(vscodeProfile.globalReplacements).toBeDefined(); // computed from customReplacements + expect(Array.isArray(vscodeProfile.globalReplacements)).toBe(true); + }); + + test('vscode.js configures .mdc to .md extension mapping', () => { + // Check that the profile object has the correct file mapping behavior (vscode converts to .md) + expect(vscodeProfile.fileMap['rules/cursor_rules.mdc']).toBe( + 'vscode_rules.md' + ); + }); + + test('vscode.js uses standard tool mappings', () => { + // Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD) + // This verifies the architectural pattern: no custom toolMappings = standard tool names + expect(vscodeProfileContent).not.toContain('toolMappings:'); + expect(vscodeProfileContent).not.toContain('apply_diff'); + expect(vscodeProfileContent).not.toContain('search_files'); + + // Verify the result: default mappings means tools keep their original names + expect(vscodeProfile.conversionConfig.toolNames.edit_file).toBe( + 'edit_file' + ); + expect(vscodeProfile.conversionConfig.toolNames.search).toBe('search'); + }); +}); diff --git a/tests/integration/profiles/windsurf-init-functionality.test.js b/tests/integration/profiles/windsurf-init-functionality.test.js index 09aa7eda..d4331084 100644 --- a/tests/integration/profiles/windsurf-init-functionality.test.js +++ b/tests/integration/profiles/windsurf-init-functionality.test.js @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { windsurfProfile } from '../../../src/profiles/windsurf.js'; describe('Windsurf Profile Initialization Functionality', () => { let windsurfProfileContent; @@ -15,25 +16,39 @@ describe('Windsurf Profile Initialization Functionality', () => { }); test('windsurf.js uses factory pattern with correct configuration', () => { + // Check for explicit, non-default values in the source file expect(windsurfProfileContent).toContain("name: 'windsurf'"); expect(windsurfProfileContent).toContain("displayName: 'Windsurf'"); - expect(windsurfProfileContent).toContain("rulesDir: '.windsurf/rules'"); - expect(windsurfProfileContent).toContain("profileDir: '.windsurf'"); + expect(windsurfProfileContent).toContain("url: 'windsurf.com'"); + expect(windsurfProfileContent).toContain("docsUrl: 'docs.windsurf.com'"); + + // Check the final computed properties on the profile object + expect(windsurfProfile.profileName).toBe('windsurf'); + expect(windsurfProfile.displayName).toBe('Windsurf'); + expect(windsurfProfile.profileDir).toBe('.windsurf'); // default + expect(windsurfProfile.rulesDir).toBe('.windsurf/rules'); // default + expect(windsurfProfile.mcpConfig).toBe(true); // default + expect(windsurfProfile.mcpConfigName).toBe('mcp.json'); // default }); test('windsurf.js configures .mdc to .md extension mapping', () => { - expect(windsurfProfileContent).toContain("fileExtension: '.mdc'"); - expect(windsurfProfileContent).toContain("targetExtension: '.md'"); + // Check that the profile object has the correct file mapping behavior (windsurf converts to .md) + expect(windsurfProfile.fileMap['rules/cursor_rules.mdc']).toBe( + 'windsurf_rules.md' + ); }); test('windsurf.js uses standard tool mappings', () => { - expect(windsurfProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD'); - // Should contain comment about standard tool names - expect(windsurfProfileContent).toContain('standard tool names'); - }); + // Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD) + // This verifies the architectural pattern: no custom toolMappings = standard tool names + expect(windsurfProfileContent).not.toContain('toolMappings:'); + expect(windsurfProfileContent).not.toContain('apply_diff'); + expect(windsurfProfileContent).not.toContain('search_files'); - test('windsurf.js contains correct URL configuration', () => { - expect(windsurfProfileContent).toContain("url: 'windsurf.com'"); - expect(windsurfProfileContent).toContain("docsUrl: 'docs.windsurf.com'"); + // Verify the result: default mappings means tools keep their original names + expect(windsurfProfile.conversionConfig.toolNames.edit_file).toBe( + 'edit_file' + ); + expect(windsurfProfile.conversionConfig.toolNames.search).toBe('search'); }); }); diff --git a/tests/unit/commands.test.js b/tests/unit/commands.test.js index d76d7779..0cbf5f71 100644 --- a/tests/unit/commands.test.js +++ b/tests/unit/commands.test.js @@ -372,9 +372,7 @@ describe('rules command', () => { expect.stringMatching(/removing rules for profile: roo/i) ); expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringMatching( - /Summary for roo: (Rules directory removed|Skipped \(default or protected files\))/i - ) + expect.stringMatching(/Summary for roo: Rule profile removed/i) ); // Should not exit with error expect(mockExit).not.toHaveBeenCalledWith(1); diff --git a/tests/unit/profiles/gemini-integration.test.js b/tests/unit/profiles/gemini-integration.test.js new file mode 100644 index 00000000..0aa768eb --- /dev/null +++ b/tests/unit/profiles/gemini-integration.test.js @@ -0,0 +1,156 @@ +import { jest } from '@jest/globals'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; + +// Mock external modules +jest.mock('child_process', () => ({ + execSync: jest.fn() +})); + +// Mock console methods +jest.mock('console', () => ({ + log: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + clear: jest.fn() +})); + +describe('Gemini Profile Integration', () => { + let tempDir; + + beforeEach(() => { + jest.clearAllMocks(); + + // Create a temporary directory for testing + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'task-master-test-')); + + // Spy on fs methods + jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); + jest.spyOn(fs, 'readFileSync').mockImplementation((filePath) => { + if (filePath.toString().includes('AGENTS.md')) { + return 'Sample AGENTS.md content for Gemini integration'; + } + return '{}'; + }); + jest.spyOn(fs, 'existsSync').mockImplementation(() => false); + jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {}); + }); + + afterEach(() => { + // Clean up the temporary directory + try { + fs.rmSync(tempDir, { recursive: true, force: true }); + } catch (err) { + console.error(`Error cleaning up: ${err.message}`); + } + }); + + // Test function that simulates the Gemini profile file copying behavior + function mockCreateGeminiStructure() { + // Gemini profile copies AGENTS.md to GEMINI.md in project root + const sourceContent = 'Sample AGENTS.md content for Gemini integration'; + fs.writeFileSync(path.join(tempDir, 'GEMINI.md'), sourceContent); + + // Gemini profile creates .gemini directory + fs.mkdirSync(path.join(tempDir, '.gemini'), { recursive: true }); + + // Gemini profile creates settings.json in .gemini directory + const settingsContent = JSON.stringify( + { + mcpServers: { + 'task-master-ai': { + command: 'npx', + args: ['-y', 'task-master-ai'], + env: { + YOUR_ANTHROPIC_API_KEY: 'your-api-key-here', + YOUR_PERPLEXITY_API_KEY: 'your-api-key-here', + YOUR_OPENAI_API_KEY: 'your-api-key-here', + YOUR_GOOGLE_API_KEY: 'your-api-key-here', + YOUR_MISTRAL_API_KEY: 'your-api-key-here', + YOUR_AZURE_OPENAI_API_KEY: 'your-api-key-here', + YOUR_AZURE_OPENAI_ENDPOINT: 'your-endpoint-here', + YOUR_OPENROUTER_API_KEY: 'your-api-key-here', + YOUR_XAI_API_KEY: 'your-api-key-here', + YOUR_OLLAMA_API_KEY: 'your-api-key-here', + YOUR_OLLAMA_BASE_URL: 'http://localhost:11434/api', + YOUR_AWS_ACCESS_KEY_ID: 'your-access-key-id', + YOUR_AWS_SECRET_ACCESS_KEY: 'your-secret-access-key', + YOUR_AWS_REGION: 'us-east-1' + } + } + } + }, + null, + 2 + ); + fs.writeFileSync( + path.join(tempDir, '.gemini', 'settings.json'), + settingsContent + ); + } + + test('creates GEMINI.md file in project root', () => { + // Act + mockCreateGeminiStructure(); + + // Assert + expect(fs.writeFileSync).toHaveBeenCalledWith( + path.join(tempDir, 'GEMINI.md'), + 'Sample AGENTS.md content for Gemini integration' + ); + }); + + test('creates .gemini profile directory', () => { + // Act + mockCreateGeminiStructure(); + + // Assert + expect(fs.mkdirSync).toHaveBeenCalledWith(path.join(tempDir, '.gemini'), { + recursive: true + }); + }); + + test('creates MCP configuration as settings.json', () => { + // Act + mockCreateGeminiStructure(); + + // Assert - Gemini profile should create settings.json instead of mcp.json + const writeFileCalls = fs.writeFileSync.mock.calls; + const settingsJsonCall = writeFileCalls.find((call) => + call[0].toString().includes('.gemini/settings.json') + ); + expect(settingsJsonCall).toBeDefined(); + }); + + test('uses settings.json instead of mcp.json', () => { + // Act + mockCreateGeminiStructure(); + + // Assert - Should use settings.json, not mcp.json + const writeFileCalls = fs.writeFileSync.mock.calls; + const mcpJsonCalls = writeFileCalls.filter((call) => + call[0].toString().includes('mcp.json') + ); + expect(mcpJsonCalls).toHaveLength(0); + + const settingsJsonCalls = writeFileCalls.filter((call) => + call[0].toString().includes('settings.json') + ); + expect(settingsJsonCalls).toHaveLength(1); + }); + + test('renames AGENTS.md to GEMINI.md', () => { + // Act + mockCreateGeminiStructure(); + + // Assert - Gemini should rename AGENTS.md to GEMINI.md + const writeFileCalls = fs.writeFileSync.mock.calls; + const geminiMdCall = writeFileCalls.find((call) => + call[0].toString().includes('GEMINI.md') + ); + expect(geminiMdCall).toBeDefined(); + expect(geminiMdCall[0]).toBe(path.join(tempDir, 'GEMINI.md')); + }); +}); diff --git a/tests/unit/profiles/mcp-config-validation.test.js b/tests/unit/profiles/mcp-config-validation.test.js index 8ed2dda9..9397ae9f 100644 --- a/tests/unit/profiles/mcp-config-validation.test.js +++ b/tests/unit/profiles/mcp-config-validation.test.js @@ -8,8 +8,8 @@ describe('MCP Configuration Validation', () => { cline: { shouldHaveMcp: false, expectedDir: '.clinerules', - expectedConfigName: 'cline_mcp_settings.json', - expectedPath: '.clinerules/cline_mcp_settings.json' + expectedConfigName: null, + expectedPath: null }, cursor: { shouldHaveMcp: true, @@ -17,6 +17,12 @@ describe('MCP Configuration Validation', () => { expectedConfigName: 'mcp.json', expectedPath: '.cursor/mcp.json' }, + gemini: { + shouldHaveMcp: true, + expectedDir: '.gemini', + expectedConfigName: 'settings.json', + expectedPath: '.gemini/settings.json' + }, roo: { shouldHaveMcp: true, expectedDir: '.roo', @@ -26,8 +32,8 @@ describe('MCP Configuration Validation', () => { trae: { shouldHaveMcp: false, expectedDir: '.trae', - expectedConfigName: 'trae_mcp_settings.json', - expectedPath: '.trae/trae_mcp_settings.json' + expectedConfigName: null, + expectedPath: null }, vscode: { shouldHaveMcp: true, @@ -111,51 +117,68 @@ describe('MCP Configuration Validation', () => { }); }); - test('should use profile-specific config name for non-MCP profiles', () => { + test('should use custom settings.json for Gemini profile', () => { + const profile = getRulesProfile('gemini'); + expect(profile.mcpConfigName).toBe('settings.json'); + }); + + test('should have null config name for non-MCP profiles', () => { const clineProfile = getRulesProfile('cline'); - expect(clineProfile.mcpConfigName).toBe('cline_mcp_settings.json'); + expect(clineProfile.mcpConfigName).toBe(null); const traeProfile = getRulesProfile('trae'); - expect(traeProfile.mcpConfigName).toBe('trae_mcp_settings.json'); + expect(traeProfile.mcpConfigName).toBe(null); + + const claudeProfile = getRulesProfile('claude'); + expect(claudeProfile.mcpConfigName).toBe(null); + + const codexProfile = getRulesProfile('codex'); + expect(codexProfile.mcpConfigName).toBe(null); }); }); describe('Profile Directory Structure', () => { test('should ensure each profile has a unique directory', () => { const profileDirs = new Set(); - // Simple profiles that use root directory (can share the same directory) - const simpleProfiles = ['claude', 'codex']; + // Profiles that use root directory (can share the same directory) + const rootProfiles = ['claude', 'codex', 'gemini']; RULE_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); - // Simple profiles can share the root directory - if (simpleProfiles.includes(profileName)) { - expect(profile.profileDir).toBe('.'); - return; + // Root profiles can share the root directory for rules + if (rootProfiles.includes(profileName) && profile.rulesDir === '.') { + expect(profile.rulesDir).toBe('.'); } - // Full profiles should have unique directories - expect(profileDirs.has(profile.profileDir)).toBe(false); - profileDirs.add(profile.profileDir); + // Profile directories should be unique (except for root profiles) + if (!rootProfiles.includes(profileName) || profile.profileDir !== '.') { + expect(profileDirs.has(profile.profileDir)).toBe(false); + profileDirs.add(profile.profileDir); + } }); }); test('should ensure profile directories follow expected naming convention', () => { - // Simple profiles that use root directory - const simpleProfiles = ['claude', 'codex']; + // Profiles that use root directory for rules + const rootRulesProfiles = ['claude', 'codex', 'gemini']; RULE_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); - // Simple profiles use root directory - if (simpleProfiles.includes(profileName)) { - expect(profile.profileDir).toBe('.'); - return; + // Some profiles use root directory for rules + if ( + rootRulesProfiles.includes(profileName) && + profile.rulesDir === '.' + ) { + expect(profile.rulesDir).toBe('.'); } - // Full profiles should follow the .name pattern - expect(profile.profileDir).toMatch(/^\.[\w-]+$/); + // Profile directories (not rules directories) should follow the .name pattern + // unless they are root profiles with profileDir = '.' + if (profile.profileDir !== '.') { + expect(profile.profileDir).toMatch(/^\.[\w-]+$/); + } }); }); }); @@ -168,6 +191,7 @@ describe('MCP Configuration Validation', () => { }); expect(mcpEnabledProfiles).toContain('cursor'); + expect(mcpEnabledProfiles).toContain('gemini'); expect(mcpEnabledProfiles).toContain('roo'); expect(mcpEnabledProfiles).toContain('vscode'); expect(mcpEnabledProfiles).toContain('windsurf'); @@ -244,4 +268,84 @@ describe('MCP Configuration Validation', () => { }); }); }); + + describe('MCP configuration validation', () => { + const mcpProfiles = ['cursor', 'gemini', 'roo', 'windsurf', 'vscode']; + const nonMcpProfiles = ['claude', 'codex', 'cline', 'trae']; + + test.each(mcpProfiles)( + 'should have valid MCP config for %s profile', + (profileName) => { + const profile = getRulesProfile(profileName); + expect(profile).toBeDefined(); + expect(profile.mcpConfig).toBe(true); + expect(profile.mcpConfigPath).toBeDefined(); + expect(typeof profile.mcpConfigPath).toBe('string'); + } + ); + + test.each(nonMcpProfiles)( + 'should not require MCP config for %s profile', + (profileName) => { + const profile = getRulesProfile(profileName); + expect(profile).toBeDefined(); + expect(profile.mcpConfig).toBe(false); + } + ); + }); + + describe('Profile structure validation', () => { + const mcpProfiles = [ + 'cursor', + 'gemini', + 'roo', + 'windsurf', + 'cline', + 'trae', + 'vscode' + ]; + const profilesWithLifecycle = ['claude']; + const profilesWithoutLifecycle = ['codex']; + + test.each(mcpProfiles)( + 'should have file mappings for %s profile', + (profileName) => { + const profile = getRulesProfile(profileName); + expect(profile).toBeDefined(); + expect(profile.fileMap).toBeDefined(); + expect(typeof profile.fileMap).toBe('object'); + expect(Object.keys(profile.fileMap).length).toBeGreaterThan(0); + } + ); + + test.each(profilesWithLifecycle)( + 'should have file mappings and lifecycle functions for %s profile', + (profileName) => { + const profile = getRulesProfile(profileName); + expect(profile).toBeDefined(); + // Claude profile has both fileMap and lifecycle functions + expect(profile.fileMap).toBeDefined(); + expect(typeof profile.fileMap).toBe('object'); + expect(Object.keys(profile.fileMap).length).toBeGreaterThan(0); + expect(typeof profile.onAddRulesProfile).toBe('function'); + expect(typeof profile.onRemoveRulesProfile).toBe('function'); + expect(typeof profile.onPostConvertRulesProfile).toBe('function'); + } + ); + + test.each(profilesWithoutLifecycle)( + 'should have file mappings without lifecycle functions for %s profile', + (profileName) => { + const profile = getRulesProfile(profileName); + expect(profile).toBeDefined(); + // Codex profile has fileMap but no lifecycle functions (simplified) + expect(profile.fileMap).toBeDefined(); + expect(typeof profile.fileMap).toBe('object'); + expect(Object.keys(profile.fileMap).length).toBeGreaterThan(0); + expect(profile.onAddRulesProfile).toBeUndefined(); + expect(profile.onRemoveRulesProfile).toBeUndefined(); + expect(profile.onPostConvertRulesProfile).toBeUndefined(); + } + ); + }); }); diff --git a/tests/unit/profiles/rule-transformer-gemini.test.js b/tests/unit/profiles/rule-transformer-gemini.test.js new file mode 100644 index 00000000..210220cd --- /dev/null +++ b/tests/unit/profiles/rule-transformer-gemini.test.js @@ -0,0 +1,70 @@ +import { jest } from '@jest/globals'; +import { getRulesProfile } from '../../../src/utils/rule-transformer.js'; +import { geminiProfile } from '../../../src/profiles/gemini.js'; + +describe('Rule Transformer - Gemini Profile', () => { + test('should have correct profile configuration', () => { + const geminiProfile = getRulesProfile('gemini'); + + expect(geminiProfile).toBeDefined(); + expect(geminiProfile.profileName).toBe('gemini'); + expect(geminiProfile.displayName).toBe('Gemini'); + expect(geminiProfile.profileDir).toBe('.gemini'); + expect(geminiProfile.rulesDir).toBe('.'); + expect(geminiProfile.mcpConfig).toBe(true); + expect(geminiProfile.mcpConfigName).toBe('settings.json'); + expect(geminiProfile.mcpConfigPath).toBe('.gemini/settings.json'); + expect(geminiProfile.includeDefaultRules).toBe(false); + expect(geminiProfile.fileMap).toEqual({ + 'AGENTS.md': 'GEMINI.md' + }); + }); + + test('should have minimal profile implementation', () => { + // Verify that gemini.js is minimal (no lifecycle functions) + expect(geminiProfile.onAddRulesProfile).toBeUndefined(); + expect(geminiProfile.onRemoveRulesProfile).toBeUndefined(); + expect(geminiProfile.onPostConvertRulesProfile).toBeUndefined(); + }); + + test('should use settings.json instead of mcp.json', () => { + const geminiProfile = getRulesProfile('gemini'); + expect(geminiProfile.mcpConfigName).toBe('settings.json'); + expect(geminiProfile.mcpConfigPath).toBe('.gemini/settings.json'); + }); + + test('should not include default rules', () => { + const geminiProfile = getRulesProfile('gemini'); + expect(geminiProfile.includeDefaultRules).toBe(false); + }); + + test('should have correct file mapping', () => { + const geminiProfile = getRulesProfile('gemini'); + expect(geminiProfile.fileMap).toEqual({ + 'AGENTS.md': 'GEMINI.md' + }); + }); + + test('should place GEMINI.md in root directory', () => { + const geminiProfile = getRulesProfile('gemini'); + // rulesDir determines where fileMap files go + expect(geminiProfile.rulesDir).toBe('.'); + // This means AGENTS.md -> GEMINI.md will be placed in the root + }); + + test('should place settings.json in .gemini directory', () => { + const geminiProfile = getRulesProfile('gemini'); + // profileDir + mcpConfigName determines MCP config location + expect(geminiProfile.profileDir).toBe('.gemini'); + expect(geminiProfile.mcpConfigName).toBe('settings.json'); + expect(geminiProfile.mcpConfigPath).toBe('.gemini/settings.json'); + }); + + test('should have proper conversion config', () => { + const geminiProfile = getRulesProfile('gemini'); + // Gemini should have the standard conversion config + expect(geminiProfile.conversionConfig).toBeDefined(); + expect(geminiProfile.globalReplacements).toBeDefined(); + expect(Array.isArray(geminiProfile.globalReplacements)).toBe(true); + }); +}); diff --git a/tests/unit/profiles/rule-transformer.test.js b/tests/unit/profiles/rule-transformer.test.js index 33d812d2..7950d738 100644 --- a/tests/unit/profiles/rule-transformer.test.js +++ b/tests/unit/profiles/rule-transformer.test.js @@ -17,6 +17,7 @@ describe('Rule Transformer - General', () => { 'cline', 'codex', 'cursor', + 'gemini', 'roo', 'trae', 'vscode', @@ -55,9 +56,6 @@ describe('Rule Transformer - General', () => { describe('Profile Structure', () => { it('should have all required properties for each profile', () => { - // Simple profiles that only copy files (no rule transformation) - const simpleProfiles = ['claude', 'codex']; - RULE_PROFILES.forEach((profile) => { const profileConfig = getRulesProfile(profile); @@ -68,50 +66,50 @@ describe('Rule Transformer - General', () => { expect(profileConfig).toHaveProperty('rulesDir'); expect(profileConfig).toHaveProperty('profileDir'); - // Simple profiles have minimal structure - if (simpleProfiles.includes(profile)) { - // For simple profiles, conversionConfig and fileMap can be empty - expect(typeof profileConfig.conversionConfig).toBe('object'); - expect(typeof profileConfig.fileMap).toBe('object'); - return; + // All profiles should have conversionConfig and fileMap objects + expect(typeof profileConfig.conversionConfig).toBe('object'); + expect(typeof profileConfig.fileMap).toBe('object'); + + // Check that conversionConfig has required structure for profiles with rules + const hasRules = Object.keys(profileConfig.fileMap).length > 0; + if (hasRules) { + expect(profileConfig.conversionConfig).toHaveProperty('profileTerms'); + expect(profileConfig.conversionConfig).toHaveProperty('toolNames'); + expect(profileConfig.conversionConfig).toHaveProperty('toolContexts'); + expect(profileConfig.conversionConfig).toHaveProperty('toolGroups'); + expect(profileConfig.conversionConfig).toHaveProperty('docUrls'); + expect(profileConfig.conversionConfig).toHaveProperty( + 'fileReferences' + ); + + // Verify arrays are actually arrays + expect( + Array.isArray(profileConfig.conversionConfig.profileTerms) + ).toBe(true); + expect(typeof profileConfig.conversionConfig.toolNames).toBe( + 'object' + ); + expect( + Array.isArray(profileConfig.conversionConfig.toolContexts) + ).toBe(true); + expect(Array.isArray(profileConfig.conversionConfig.toolGroups)).toBe( + true + ); + expect(Array.isArray(profileConfig.conversionConfig.docUrls)).toBe( + true + ); } - - // Check that conversionConfig has required structure for full profiles - expect(profileConfig.conversionConfig).toHaveProperty('profileTerms'); - expect(profileConfig.conversionConfig).toHaveProperty('toolNames'); - expect(profileConfig.conversionConfig).toHaveProperty('toolContexts'); - expect(profileConfig.conversionConfig).toHaveProperty('toolGroups'); - expect(profileConfig.conversionConfig).toHaveProperty('docUrls'); - expect(profileConfig.conversionConfig).toHaveProperty('fileReferences'); - - // Verify arrays are actually arrays - expect(Array.isArray(profileConfig.conversionConfig.profileTerms)).toBe( - true - ); - expect(typeof profileConfig.conversionConfig.toolNames).toBe('object'); - expect(Array.isArray(profileConfig.conversionConfig.toolContexts)).toBe( - true - ); - expect(Array.isArray(profileConfig.conversionConfig.toolGroups)).toBe( - true - ); - expect(Array.isArray(profileConfig.conversionConfig.docUrls)).toBe( - true - ); }); }); it('should have valid fileMap with required files for each profile', () => { - const expectedFiles = [ + const expectedRuleFiles = [ 'cursor_rules.mdc', 'dev_workflow.mdc', 'self_improve.mdc', 'taskmaster.mdc' ]; - // Simple profiles that only copy files (no rule transformation) - const simpleProfiles = ['claude', 'codex']; - RULE_PROFILES.forEach((profile) => { const profileConfig = getRulesProfile(profile); @@ -120,33 +118,43 @@ describe('Rule Transformer - General', () => { expect(typeof profileConfig.fileMap).toBe('object'); expect(profileConfig.fileMap).not.toBeNull(); - // Simple profiles can have empty fileMap since they don't transform rules - if (simpleProfiles.includes(profile)) { - return; - } - - // Check that fileMap is not empty for full profiles const fileMapKeys = Object.keys(profileConfig.fileMap); + + // All profiles should have some fileMap entries now expect(fileMapKeys.length).toBeGreaterThan(0); - // Check that all expected source files are defined in fileMap - expectedFiles.forEach((expectedFile) => { - expect(fileMapKeys).toContain(expectedFile); - expect(typeof profileConfig.fileMap[expectedFile]).toBe('string'); - expect(profileConfig.fileMap[expectedFile].length).toBeGreaterThan(0); - }); + // Check if this profile has rule files or asset files + const hasRuleFiles = expectedRuleFiles.some((file) => + fileMapKeys.includes(file) + ); + const hasAssetFiles = fileMapKeys.some( + (file) => !expectedRuleFiles.includes(file) + ); - // Verify fileMap has exactly the expected files - expect(fileMapKeys.sort()).toEqual(expectedFiles.sort()); + if (hasRuleFiles) { + // Profiles with rule files should have all expected rule files + expectedRuleFiles.forEach((expectedFile) => { + expect(fileMapKeys).toContain(expectedFile); + expect(typeof profileConfig.fileMap[expectedFile]).toBe('string'); + expect(profileConfig.fileMap[expectedFile].length).toBeGreaterThan( + 0 + ); + }); + } + + if (hasAssetFiles) { + // Profiles with asset files (like Claude/Codex) should have valid asset mappings + fileMapKeys.forEach((key) => { + expect(typeof profileConfig.fileMap[key]).toBe('string'); + expect(profileConfig.fileMap[key].length).toBeGreaterThan(0); + }); + } }); }); }); describe('MCP Configuration Properties', () => { it('should have all required MCP properties for each profile', () => { - // Simple profiles that only copy files (no MCP configuration) - const simpleProfiles = ['claude', 'codex']; - RULE_PROFILES.forEach((profile) => { const profileConfig = getRulesProfile(profile); @@ -155,23 +163,23 @@ describe('Rule Transformer - General', () => { expect(profileConfig).toHaveProperty('mcpConfigName'); expect(profileConfig).toHaveProperty('mcpConfigPath'); - // Simple profiles have no MCP configuration - if (simpleProfiles.includes(profile)) { - expect(profileConfig.mcpConfig).toBe(false); + // Check types based on MCP configuration + expect(typeof profileConfig.mcpConfig).toBe('boolean'); + + if (profileConfig.mcpConfig === false) { + // Profiles without MCP configuration expect(profileConfig.mcpConfigName).toBe(null); expect(profileConfig.mcpConfigPath).toBe(null); - return; + } else { + // Profiles with MCP configuration + expect(typeof profileConfig.mcpConfigName).toBe('string'); + expect(typeof profileConfig.mcpConfigPath).toBe('string'); + + // Check that mcpConfigPath is properly constructed + expect(profileConfig.mcpConfigPath).toBe( + `${profileConfig.profileDir}/${profileConfig.mcpConfigName}` + ); } - - // Check types for full profiles - expect(typeof profileConfig.mcpConfig).toBe('boolean'); - expect(typeof profileConfig.mcpConfigName).toBe('string'); - expect(typeof profileConfig.mcpConfigPath).toBe('string'); - - // Check that mcpConfigPath is properly constructed - expect(profileConfig.mcpConfigPath).toBe( - `${profileConfig.profileDir}/${profileConfig.mcpConfigName}` - ); }); }); @@ -184,8 +192,8 @@ describe('Rule Transformer - General', () => { }, cline: { mcpConfig: false, - mcpConfigName: 'cline_mcp_settings.json', - expectedPath: '.clinerules/cline_mcp_settings.json' + mcpConfigName: null, + expectedPath: null }, codex: { mcpConfig: false, @@ -197,6 +205,11 @@ describe('Rule Transformer - General', () => { mcpConfigName: 'mcp.json', expectedPath: '.cursor/mcp.json' }, + gemini: { + mcpConfig: true, + mcpConfigName: 'settings.json', + expectedPath: '.gemini/settings.json' + }, roo: { mcpConfig: true, mcpConfigName: 'mcp.json', @@ -204,8 +217,8 @@ describe('Rule Transformer - General', () => { }, trae: { mcpConfig: false, - mcpConfigName: 'trae_mcp_settings.json', - expectedPath: '.trae/trae_mcp_settings.json' + mcpConfigName: null, + expectedPath: null }, vscode: { mcpConfig: true, @@ -230,31 +243,28 @@ describe('Rule Transformer - General', () => { }); it('should have consistent profileDir and mcpConfigPath relationship', () => { - // Simple profiles that only copy files (no MCP configuration) - const simpleProfiles = ['claude', 'codex']; - RULE_PROFILES.forEach((profile) => { const profileConfig = getRulesProfile(profile); - // Simple profiles have null mcpConfigPath - if (simpleProfiles.includes(profile)) { + if (profileConfig.mcpConfig === false) { + // Profiles without MCP configuration have null mcpConfigPath expect(profileConfig.mcpConfigPath).toBe(null); - return; + } else { + // Profiles with MCP configuration should have valid paths + // The mcpConfigPath should start with the profileDir + expect(profileConfig.mcpConfigPath).toMatch( + new RegExp( + `^${profileConfig.profileDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/` + ) + ); + + // The mcpConfigPath should end with the mcpConfigName + expect(profileConfig.mcpConfigPath).toMatch( + new RegExp( + `${profileConfig.mcpConfigName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$` + ) + ); } - - // The mcpConfigPath should start with the profileDir - expect(profileConfig.mcpConfigPath).toMatch( - new RegExp( - `^${profileConfig.profileDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/` - ) - ); - - // The mcpConfigPath should end with the mcpConfigName - expect(profileConfig.mcpConfigPath).toMatch( - new RegExp( - `${profileConfig.mcpConfigName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$` - ) - ); }); }); diff --git a/tests/unit/profiles/selective-profile-removal.test.js b/tests/unit/profiles/selective-profile-removal.test.js index d9aaeec2..a3a4a24e 100644 --- a/tests/unit/profiles/selective-profile-removal.test.js +++ b/tests/unit/profiles/selective-profile-removal.test.js @@ -136,8 +136,8 @@ describe('Selective Rules Removal', () => { expect(result.filesRemoved).toEqual([ 'cursor_rules.mdc', 'taskmaster/dev_workflow.mdc', - 'taskmaster/taskmaster.mdc', - 'self_improve.mdc' + 'self_improve.mdc', + 'taskmaster/taskmaster.mdc' ]); expect(result.notice).toContain('Preserved 2 existing rule files'); @@ -226,8 +226,8 @@ describe('Selective Rules Removal', () => { expect(result.filesRemoved).toEqual([ 'cursor_rules.mdc', 'taskmaster/dev_workflow.mdc', - 'taskmaster/taskmaster.mdc', - 'self_improve.mdc' + 'self_improve.mdc', + 'taskmaster/taskmaster.mdc' ]); // The function may fail due to directory reading issues in the test environment, @@ -354,8 +354,8 @@ describe('Selective Rules Removal', () => { // Mock sequence: only Task Master rules, rules dir removed, but profile dir not empty due to MCP mockReaddirSync .mockReturnValueOnce(['cursor_rules.mdc']) // Only Task Master files - .mockReturnValueOnce([]) // rules dir empty after removal - .mockReturnValueOnce(['mcp.json']); // Profile dir has MCP config remaining + .mockReturnValueOnce(['my_custom_rule.mdc']) // rules dir has other files remaining + .mockReturnValueOnce(['rules', 'mcp.json']); // Profile dir has rules and MCP config remaining // Mock MCP config with multiple servers (Task Master will be removed, others preserved) const mockMcpConfig = { @@ -400,8 +400,9 @@ describe('Selective Rules Removal', () => { // Mock sequence: only Task Master rules, rules dir removed, but profile dir has other files/folders mockReaddirSync - .mockReturnValueOnce(['cursor_rules.mdc']) // Only Task Master files - .mockReturnValueOnce([]) // rules dir empty after removal + .mockReturnValueOnce(['cursor_rules.mdc']) // Only Task Master files (initial check) + .mockReturnValueOnce(['cursor_rules.mdc']) // Task Master files list for filtering + .mockReturnValueOnce([]) // Rules dir empty after removal (not used since no remaining files) .mockReturnValueOnce(['workflows', 'custom-config.json']); // Profile dir has other files/folders // Mock MCP config with only Task Master (will be completely deleted) @@ -420,7 +421,7 @@ describe('Selective Rules Removal', () => { expect(result.success).toBe(true); expect(result.profileDirRemoved).toBe(false); expect(result.mcpResult.deleted).toBe(true); - expect(result.notice).toContain('Preserved 2 existing files/folders'); + expect(result.notice).toContain('existing files/folders in .cursor'); // Verify profile directory was NOT removed (other files/folders exist) expect(mockRmSync).not.toHaveBeenCalledWith( @@ -587,8 +588,30 @@ describe('Selective Rules Removal', () => { // Mock mixed scenario: some Task Master files, some existing files, other MCP servers mockExistsSync.mockImplementation((filePath) => { - if (filePath.includes('.cursor')) return true; - if (filePath.includes('mcp.json')) return true; + // Only .cursor directories exist + if (filePath === path.join(projectRoot, '.cursor')) return true; + if (filePath === path.join(projectRoot, '.cursor/rules')) return true; + if (filePath === path.join(projectRoot, '.cursor/mcp.json')) + return true; + // Only cursor_rules.mdc exists, not the other taskmaster files + if ( + filePath === path.join(projectRoot, '.cursor/rules/cursor_rules.mdc') + ) + return true; + if ( + filePath === + path.join(projectRoot, '.cursor/rules/taskmaster/dev_workflow.mdc') + ) + return false; + if ( + filePath === path.join(projectRoot, '.cursor/rules/self_improve.mdc') + ) + return false; + if ( + filePath === + path.join(projectRoot, '.cursor/rules/taskmaster/taskmaster.mdc') + ) + return false; return false; }); diff --git a/tests/unit/profiles/subdirectory-support.test.js b/tests/unit/profiles/subdirectory-support.test.js index 5570c6e8..ca91c714 100644 --- a/tests/unit/profiles/subdirectory-support.test.js +++ b/tests/unit/profiles/subdirectory-support.test.js @@ -8,10 +8,10 @@ describe('Rules Subdirectory Support Feature', () => { expect(cursorProfile.supportsRulesSubdirectories).toBe(true); // Verify that Cursor uses taskmaster subdirectories in its file mapping - expect(cursorProfile.fileMap['dev_workflow.mdc']).toBe( + expect(cursorProfile.fileMap['rules/dev_workflow.mdc']).toBe( 'taskmaster/dev_workflow.mdc' ); - expect(cursorProfile.fileMap['taskmaster.mdc']).toBe( + expect(cursorProfile.fileMap['rules/taskmaster.mdc']).toBe( 'taskmaster/taskmaster.mdc' ); }); @@ -26,10 +26,10 @@ describe('Rules Subdirectory Support Feature', () => { // Verify that these profiles do NOT use taskmaster subdirectories in their file mapping const expectedExt = profile.targetExtension || '.md'; - expect(profile.fileMap['dev_workflow.mdc']).toBe( + expect(profile.fileMap['rules/dev_workflow.mdc']).toBe( `dev_workflow${expectedExt}` ); - expect(profile.fileMap['taskmaster.mdc']).toBe( + expect(profile.fileMap['rules/taskmaster.mdc']).toBe( `taskmaster${expectedExt}` ); });