Unify and streamline profile system architecture (#853)
* move claude rules and commands to assets/claude * update claude profile to copy assets/claude to .claude * fix formatting * feat(profiles): Implement unified profile system - Convert Claude and Codex profiles to use createProfile() factory - Remove simple vs complex profile distinction in rule transformer - Unify convertAllRulesToProfileRules() to handle all profiles consistently - Fix mcpConfigPath construction in base-profile.js for null mcpConfigName - Update terminology from 'simpleProfiles' to 'assetOnlyProfiles' throughout - Ensure Claude .claude directory copying works in both CLI and MCP contexts - All profiles now follow same execution flow with proper lifecycle functions Changes: - src/profiles/claude.js: Convert to createProfile() factory pattern - src/profiles/codex.js: Convert to createProfile() factory pattern - src/utils/rule-transformer.js: Unified profile handling logic - src/utils/profiles.js: Remove simple profile categorization - src/profiles/base-profile.js: Fix mcpConfigPath construction - scripts/modules/commands.js: Update variable naming - tests/: Update all tests for unified system and terminology Fixes Claude profile asset copying issue in MCP context. All tests passing (617 passed, 11 skipped). * re-checkin claude files * fix formatting * chore: clean up test Claude rules files * chore: add changeset for unified profile system * add claude files back * add changeset * restore proper gitignore * remove claude agents file from root * remove incorrect doc * simplify profiles and update tests * update changeset * update changeset * remove profile specific code * streamline profiles with defaults and update tests * update changeset * add newline at end of gitignore * restore changes * streamline profiles with defaults; update tests and add vscode test * update rule profile tests * update wording for clearer profile management * refactor and clarify terminology * use original projectRoot var name * revert param desc * use updated claude assets from neno * add "YOUR_" before api key here * streamline codex profile * add gemini profile * update gemini profile * update tests * relocate function * update rules interactive setup Gemini desc * remove duplicative code * add comma
This commit is contained in:
5
.changeset/spicy-badgers-fail.md
Normal file
5
.changeset/spicy-badgers-fail.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"task-master-ai": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Unify and streamline profile system architecture for improved maintainability
|
||||||
147
assets/claude/TM_COMMANDS_GUIDE.md
Normal file
147
assets/claude/TM_COMMANDS_GUIDE.md
Normal file
@@ -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 <status>` - Filter by status
|
||||||
|
- `/project:tm/show <id>` - 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 <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>`
|
||||||
|
|
||||||
|
### Task Analysis
|
||||||
|
- `/project:tm/analyze-complexity` - AI analysis
|
||||||
|
- `/project:tm/complexity-report` - View report
|
||||||
|
- `/project:tm/expand <id>` - 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 <id>
|
||||||
|
/project:tm/set-status/to-done <id>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task Breakdown
|
||||||
|
```
|
||||||
|
/project:tm/show <id>
|
||||||
|
/project:tm/expand <id>
|
||||||
|
/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
|
||||||
55
assets/claude/commands/tm/add-dependency/add-dependency.md
Normal file
55
assets/claude/commands/tm/add-dependency/add-dependency.md
Normal file
@@ -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=<task-id> --depends-on=<dependency-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
```
|
||||||
76
assets/claude/commands/tm/add-subtask/add-subtask.md
Normal file
76
assets/claude/commands/tm/add-subtask/add-subtask.md
Normal file
@@ -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=<id> --title="<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
|
||||||
@@ -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
|
||||||
78
assets/claude/commands/tm/add-task/add-task.md
Normal file
78
assets/claude/commands/tm/add-task/add-task.md
Normal file
@@ -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.
|
||||||
@@ -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
|
||||||
|
```
|
||||||
@@ -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
|
||||||
|
```
|
||||||
86
assets/claude/commands/tm/clear-subtasks/clear-subtasks.md
Normal file
86
assets/claude/commands/tm/clear-subtasks/clear-subtasks.md
Normal file
@@ -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
|
||||||
|
```
|
||||||
117
assets/claude/commands/tm/complexity-report/complexity-report.md
Normal file
117
assets/claude/commands/tm/complexity-report/complexity-report.md
Normal file
@@ -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
|
||||||
|
```
|
||||||
51
assets/claude/commands/tm/expand/expand-all-tasks.md
Normal file
51
assets/claude/commands/tm/expand/expand-all-tasks.md
Normal file
@@ -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
|
||||||
49
assets/claude/commands/tm/expand/expand-task.md
Normal file
49
assets/claude/commands/tm/expand/expand-task.md
Normal file
@@ -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
|
||||||
@@ -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
|
||||||
121
assets/claude/commands/tm/generate/generate-tasks.md
Normal file
121
assets/claude/commands/tm/generate/generate-tasks.md
Normal file
@@ -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
|
||||||
81
assets/claude/commands/tm/help.md
Normal file
81
assets/claude/commands/tm/help.md
Normal file
@@ -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>`
|
||||||
46
assets/claude/commands/tm/init/init-project-quick.md
Normal file
46
assets/claude/commands/tm/init/init-project-quick.md
Normal file
@@ -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!
|
||||||
50
assets/claude/commands/tm/init/init-project.md
Normal file
50
assets/claude/commands/tm/init/init-project.md
Normal file
@@ -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
|
||||||
|
```
|
||||||
103
assets/claude/commands/tm/learn.md
Normal file
103
assets/claude/commands/tm/learn.md
Normal file
@@ -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>
|
||||||
39
assets/claude/commands/tm/list/list-tasks-by-status.md
Normal file
39
assets/claude/commands/tm/list/list-tasks-by-status.md
Normal file
@@ -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
|
||||||
29
assets/claude/commands/tm/list/list-tasks-with-subtasks.md
Normal file
29
assets/claude/commands/tm/list/list-tasks-with-subtasks.md
Normal file
@@ -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.
|
||||||
43
assets/claude/commands/tm/list/list-tasks.md
Normal file
43
assets/claude/commands/tm/list/list-tasks.md
Normal file
@@ -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
|
||||||
51
assets/claude/commands/tm/models/setup-models.md
Normal file
51
assets/claude/commands/tm/models/setup-models.md
Normal file
@@ -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
|
||||||
51
assets/claude/commands/tm/models/view-models.md
Normal file
51
assets/claude/commands/tm/models/view-models.md
Normal file
@@ -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
|
||||||
66
assets/claude/commands/tm/next/next-task.md
Normal file
66
assets/claude/commands/tm/next/next-task.md
Normal file
@@ -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.
|
||||||
@@ -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
|
||||||
49
assets/claude/commands/tm/parse-prd/parse-prd.md
Normal file
49
assets/claude/commands/tm/parse-prd/parse-prd.md
Normal file
@@ -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
|
||||||
@@ -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
|
||||||
|
```
|
||||||
84
assets/claude/commands/tm/remove-subtask/remove-subtask.md
Normal file
84
assets/claude/commands/tm/remove-subtask/remove-subtask.md
Normal file
@@ -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
|
||||||
107
assets/claude/commands/tm/remove-task/remove-task.md
Normal file
107
assets/claude/commands/tm/remove-task/remove-task.md
Normal file
@@ -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
|
||||||
55
assets/claude/commands/tm/set-status/to-cancelled.md
Normal file
55
assets/claude/commands/tm/set-status/to-cancelled.md
Normal file
@@ -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
|
||||||
47
assets/claude/commands/tm/set-status/to-deferred.md
Normal file
47
assets/claude/commands/tm/set-status/to-deferred.md
Normal file
@@ -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
|
||||||
44
assets/claude/commands/tm/set-status/to-done.md
Normal file
44
assets/claude/commands/tm/set-status/to-done.md
Normal file
@@ -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
|
||||||
36
assets/claude/commands/tm/set-status/to-in-progress.md
Normal file
36
assets/claude/commands/tm/set-status/to-in-progress.md
Normal file
@@ -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
|
||||||
32
assets/claude/commands/tm/set-status/to-pending.md
Normal file
32
assets/claude/commands/tm/set-status/to-pending.md
Normal file
@@ -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
|
||||||
40
assets/claude/commands/tm/set-status/to-review.md
Normal file
40
assets/claude/commands/tm/set-status/to-review.md
Normal file
@@ -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
|
||||||
117
assets/claude/commands/tm/setup/install-taskmaster.md
Normal file
117
assets/claude/commands/tm/setup/install-taskmaster.md
Normal file
@@ -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!
|
||||||
22
assets/claude/commands/tm/setup/quick-install-taskmaster.md
Normal file
22
assets/claude/commands/tm/setup/quick-install-taskmaster.md
Normal file
@@ -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.
|
||||||
82
assets/claude/commands/tm/show/show-task.md
Normal file
82
assets/claude/commands/tm/show/show-task.md
Normal file
@@ -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
|
||||||
64
assets/claude/commands/tm/status/project-status.md
Normal file
64
assets/claude/commands/tm/status/project-status.md
Normal file
@@ -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
|
||||||
117
assets/claude/commands/tm/sync-readme/sync-readme.md
Normal file
117
assets/claude/commands/tm/sync-readme/sync-readme.md
Normal file
@@ -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
|
||||||
146
assets/claude/commands/tm/tm-main.md
Normal file
146
assets/claude/commands/tm/tm-main.md
Normal file
@@ -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.
|
||||||
119
assets/claude/commands/tm/update/update-single-task.md
Normal file
119
assets/claude/commands/tm/update/update-single-task.md
Normal file
@@ -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
|
||||||
72
assets/claude/commands/tm/update/update-task.md
Normal file
72
assets/claude/commands/tm/update/update-task.md
Normal file
@@ -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.
|
||||||
108
assets/claude/commands/tm/update/update-tasks-from-id.md
Normal file
108
assets/claude/commands/tm/update/update-tasks-from-id.md
Normal file
@@ -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
|
||||||
97
assets/claude/commands/tm/utils/analyze-project.md
Normal file
97
assets/claude/commands/tm/utils/analyze-project.md
Normal file
@@ -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.
|
||||||
@@ -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
|
||||||
97
assets/claude/commands/tm/workflows/auto-implement-tasks.md
Normal file
97
assets/claude/commands/tm/workflows/auto-implement-tasks.md
Normal file
@@ -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.
|
||||||
77
assets/claude/commands/tm/workflows/command-pipeline.md
Normal file
77
assets/claude/commands/tm/workflows/command-pipeline.md
Normal file
@@ -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`
|
||||||
55
assets/claude/commands/tm/workflows/smart-workflow.md
Normal file
55
assets/claude/commands/tm/workflows/smart-workflow.md
Normal file
@@ -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
|
||||||
@@ -81,7 +81,8 @@
|
|||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@anthropic-ai/claude-code": "^1.0.25",
|
"@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": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
|
|||||||
@@ -4021,10 +4021,6 @@ Examples:
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
profileConfig
|
profileConfig
|
||||||
);
|
);
|
||||||
if (typeof profileConfig.onAddRulesProfile === 'function') {
|
|
||||||
const assetsDir = path.join(projectRoot, 'assets');
|
|
||||||
profileConfig.onAddRulesProfile(projectRoot, assetsDir);
|
|
||||||
}
|
|
||||||
console.log(
|
console.log(
|
||||||
chalk.blue(`Completed adding rules for profile: ${profile}`)
|
chalk.blue(`Completed adding rules for profile: ${profile}`)
|
||||||
);
|
);
|
||||||
@@ -4054,37 +4050,27 @@ Examples:
|
|||||||
|
|
||||||
// Print summary for additions
|
// Print summary for additions
|
||||||
if (action === RULES_ACTIONS.ADD && addResults.length > 0) {
|
if (action === RULES_ACTIONS.ADD && addResults.length > 0) {
|
||||||
const {
|
const { allSuccessfulProfiles, totalSuccess, totalFailed } =
|
||||||
allSuccessfulProfiles,
|
categorizeProfileResults(addResults);
|
||||||
totalSuccess,
|
|
||||||
totalFailed,
|
|
||||||
simpleProfiles
|
|
||||||
} = categorizeProfileResults(addResults);
|
|
||||||
|
|
||||||
if (allSuccessfulProfiles.length > 0) {
|
if (allSuccessfulProfiles.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.green(
|
chalk.green(
|
||||||
`\nSuccessfully added rules for: ${allSuccessfulProfiles.join(', ')}`
|
`\nSuccessfully processed profiles: ${allSuccessfulProfiles.join(', ')}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create a more descriptive summary
|
// Create a descriptive summary
|
||||||
if (totalSuccess > 0 && simpleProfiles.length > 0) {
|
if (totalSuccess > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.green(
|
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(
|
console.log(
|
||||||
chalk.green(
|
chalk.green(
|
||||||
`Total: ${totalSuccess} rules added, ${totalFailed} failed.`
|
`Total: ${allSuccessfulProfiles.length} profile(s) set up successfully.`
|
||||||
)
|
|
||||||
);
|
|
||||||
} else if (simpleProfiles.length > 0) {
|
|
||||||
console.log(
|
|
||||||
chalk.green(
|
|
||||||
`Total: ${simpleProfiles.length} integration guide(s) copied.`
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
* - cline: Cline IDE rules
|
||||||
* - codex: Codex integration
|
* - codex: Codex integration
|
||||||
* - cursor: Cursor IDE rules
|
* - cursor: Cursor IDE rules
|
||||||
|
* - gemini: Gemini integration
|
||||||
* - roo: Roo Code IDE rules
|
* - roo: Roo Code IDE rules
|
||||||
* - trae: Trae IDE rules
|
* - trae: Trae IDE rules
|
||||||
* - vscode: VS Code with GitHub Copilot integration
|
* - vscode: VS Code with GitHub Copilot integration
|
||||||
@@ -29,6 +30,7 @@ export const RULE_PROFILES = [
|
|||||||
'cline',
|
'cline',
|
||||||
'codex',
|
'codex',
|
||||||
'cursor',
|
'cursor',
|
||||||
|
'gemini',
|
||||||
'roo',
|
'roo',
|
||||||
'trae',
|
'trae',
|
||||||
'vscode',
|
'vscode',
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ import path from 'path';
|
|||||||
* @param {string} [editorConfig.targetExtension='.md'] - Target file extension
|
* @param {string} [editorConfig.targetExtension='.md'] - Target file extension
|
||||||
* @param {Object} [editorConfig.toolMappings={}] - Tool name mappings
|
* @param {Object} [editorConfig.toolMappings={}] - Tool name mappings
|
||||||
* @param {Array} [editorConfig.customReplacements=[]] - Custom text replacements
|
* @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.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.onAdd] - Lifecycle hook for profile addition
|
||||||
* @param {Function} [editorConfig.onRemove] - Lifecycle hook for profile removal
|
* @param {Function} [editorConfig.onRemove] - Lifecycle hook for profile removal
|
||||||
* @param {Function} [editorConfig.onPostConvert] - Lifecycle hook for post-conversion
|
* @param {Function} [editorConfig.onPostConvert] - Lifecycle hook for post-conversion
|
||||||
@@ -29,34 +30,38 @@ export function createProfile(editorConfig) {
|
|||||||
displayName = name,
|
displayName = name,
|
||||||
url,
|
url,
|
||||||
docsUrl,
|
docsUrl,
|
||||||
profileDir,
|
profileDir = `.${name.toLowerCase()}`,
|
||||||
rulesDir = `${profileDir}/rules`,
|
rulesDir = `${profileDir}/rules`,
|
||||||
mcpConfig = true,
|
mcpConfig = true,
|
||||||
mcpConfigName = 'mcp.json',
|
mcpConfigName = mcpConfig ? 'mcp.json' : null,
|
||||||
fileExtension = '.mdc',
|
fileExtension = '.mdc',
|
||||||
targetExtension = '.md',
|
targetExtension = '.md',
|
||||||
toolMappings = {},
|
toolMappings = {},
|
||||||
customReplacements = [],
|
customReplacements = [],
|
||||||
customFileMap = {},
|
fileMap = {},
|
||||||
supportsRulesSubdirectories = false,
|
supportsRulesSubdirectories = false,
|
||||||
|
includeDefaultRules = true,
|
||||||
onAdd,
|
onAdd,
|
||||||
onRemove,
|
onRemove,
|
||||||
onPostConvert
|
onPostConvert
|
||||||
} = editorConfig;
|
} = editorConfig;
|
||||||
|
|
||||||
const mcpConfigPath = `${profileDir}/${mcpConfigName}`;
|
const mcpConfigPath = mcpConfigName ? `${profileDir}/${mcpConfigName}` : null;
|
||||||
|
|
||||||
// Standard file mapping with custom overrides
|
// Standard file mapping with custom overrides
|
||||||
// Use taskmaster subdirectory only if profile supports it
|
// Use taskmaster subdirectory only if profile supports it
|
||||||
const taskmasterPrefix = supportsRulesSubdirectories ? 'taskmaster/' : '';
|
const taskmasterPrefix = supportsRulesSubdirectories ? 'taskmaster/' : '';
|
||||||
const defaultFileMap = {
|
const defaultFileMap = {
|
||||||
'cursor_rules.mdc': `${name.toLowerCase()}_rules${targetExtension}`,
|
'rules/cursor_rules.mdc': `${name.toLowerCase()}_rules${targetExtension}`,
|
||||||
'dev_workflow.mdc': `${taskmasterPrefix}dev_workflow${targetExtension}`,
|
'rules/dev_workflow.mdc': `${taskmasterPrefix}dev_workflow${targetExtension}`,
|
||||||
'self_improve.mdc': `self_improve${targetExtension}`,
|
'rules/self_improve.mdc': `self_improve${targetExtension}`,
|
||||||
'taskmaster.mdc': `${taskmasterPrefix}taskmaster${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
|
// Base global replacements that work for all editors
|
||||||
const baseGlobalReplacements = [
|
const baseGlobalReplacements = [
|
||||||
@@ -187,7 +192,8 @@ export function createProfile(editorConfig) {
|
|||||||
replacement: (match, text, filePath) => {
|
replacement: (match, text, filePath) => {
|
||||||
const baseName = path.basename(filePath, '.mdc');
|
const baseName = path.basename(filePath, '.mdc');
|
||||||
const newFileName =
|
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)
|
// Update the link text to match the new filename (strip directory path for display)
|
||||||
const newLinkText = path.basename(newFileName);
|
const newLinkText = path.basename(newFileName);
|
||||||
// For Cursor, keep the mdc: protocol; for others, use standard relative paths
|
// For Cursor, keep the mdc: protocol; for others, use standard relative paths
|
||||||
@@ -201,8 +207,8 @@ export function createProfile(editorConfig) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function getTargetRuleFilename(sourceFilename) {
|
function getTargetRuleFilename(sourceFilename) {
|
||||||
if (fileMap[sourceFilename]) {
|
if (finalFileMap[sourceFilename]) {
|
||||||
return fileMap[sourceFilename];
|
return finalFileMap[sourceFilename];
|
||||||
}
|
}
|
||||||
return targetExtension !== fileExtension
|
return targetExtension !== fileExtension
|
||||||
? sourceFilename.replace(
|
? sourceFilename.replace(
|
||||||
@@ -221,7 +227,8 @@ export function createProfile(editorConfig) {
|
|||||||
mcpConfigName,
|
mcpConfigName,
|
||||||
mcpConfigPath,
|
mcpConfigPath,
|
||||||
supportsRulesSubdirectories,
|
supportsRulesSubdirectories,
|
||||||
fileMap,
|
includeDefaultRules,
|
||||||
|
fileMap: finalFileMap,
|
||||||
globalReplacements: baseGlobalReplacements,
|
globalReplacements: baseGlobalReplacements,
|
||||||
conversionConfig,
|
conversionConfig,
|
||||||
getTargetRuleFilename,
|
getTargetRuleFilename,
|
||||||
|
|||||||
@@ -2,58 +2,96 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { isSilentMode, log } from '../../scripts/modules/utils.js';
|
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
|
// Lifecycle functions for Claude Code profile
|
||||||
function onAddRulesProfile(targetDir, assetsDir) {
|
function onAddRulesProfile(targetDir, assetsDir) {
|
||||||
// Use the provided assets directory to find the source file
|
// Copy .claude directory recursively
|
||||||
const sourceFile = path.join(assetsDir, 'AGENTS.md');
|
const claudeSourceDir = path.join(assetsDir, 'claude');
|
||||||
const destFile = path.join(targetDir, 'CLAUDE.md');
|
const claudeDestDir = path.join(targetDir, '.claude');
|
||||||
|
|
||||||
if (fs.existsSync(sourceFile)) {
|
if (!fs.existsSync(claudeSourceDir)) {
|
||||||
try {
|
log(
|
||||||
fs.copyFileSync(sourceFile, destFile);
|
'error',
|
||||||
log('debug', `[Claude] Copied AGENTS.md to ${destFile}`);
|
`[Claude] Source directory does not exist: ${claudeSourceDir}`
|
||||||
} catch (err) {
|
);
|
||||||
log('error', `[Claude] Failed to copy AGENTS.md: ${err.message}`);
|
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) {
|
function onRemoveRulesProfile(targetDir) {
|
||||||
const claudeFile = path.join(targetDir, 'CLAUDE.md');
|
// Remove .claude directory recursively
|
||||||
if (fs.existsSync(claudeFile)) {
|
const claudeDir = path.join(targetDir, '.claude');
|
||||||
try {
|
if (removeDirectoryRecursive(claudeDir)) {
|
||||||
fs.rmSync(claudeFile, { force: true });
|
log('debug', `[Claude] Removed .claude directory from ${claudeDir}`);
|
||||||
log('debug', `[Claude] Removed CLAUDE.md from ${claudeFile}`);
|
|
||||||
} catch (err) {
|
|
||||||
log('error', `[Claude] Failed to remove CLAUDE.md: ${err.message}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
||||||
|
// For Claude, post-convert is the same as add since we don't transform rules
|
||||||
onAddRulesProfile(targetDir, assetsDir);
|
onAddRulesProfile(targetDir, assetsDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple filename function
|
// Create and export claude profile using the base factory
|
||||||
function getTargetRuleFilename(sourceFilename) {
|
export const claudeProfile = createProfile({
|
||||||
return sourceFilename;
|
name: 'claude',
|
||||||
}
|
|
||||||
|
|
||||||
// Simple profile configuration - bypasses base-profile system
|
|
||||||
export const claudeProfile = {
|
|
||||||
profileName: 'claude',
|
|
||||||
displayName: 'Claude Code',
|
displayName: 'Claude Code',
|
||||||
|
url: 'claude.ai',
|
||||||
|
docsUrl: 'docs.anthropic.com/en/docs/claude-code',
|
||||||
profileDir: '.', // Root directory
|
profileDir: '.', // Root directory
|
||||||
rulesDir: '.', // No rules directory needed
|
rulesDir: '.', // No specific rules directory needed
|
||||||
mcpConfig: false, // No MCP config needed
|
mcpConfig: false,
|
||||||
mcpConfigName: null,
|
mcpConfigName: null,
|
||||||
mcpConfigPath: null,
|
includeDefaultRules: false,
|
||||||
conversionConfig: {},
|
fileMap: {
|
||||||
fileMap: {},
|
'AGENTS.md': 'CLAUDE.md'
|
||||||
globalReplacements: [],
|
},
|
||||||
getTargetRuleFilename,
|
onAdd: onAddRulesProfile,
|
||||||
onAddRulesProfile,
|
onRemove: onRemoveRulesProfile,
|
||||||
onRemoveRulesProfile,
|
onPostConvert: onPostConvertRulesProfile
|
||||||
onPostConvertRulesProfile
|
});
|
||||||
};
|
|
||||||
|
// Export lifecycle functions separately to avoid naming conflicts
|
||||||
|
export { onAddRulesProfile, onRemoveRulesProfile, onPostConvertRulesProfile };
|
||||||
|
|||||||
@@ -9,12 +9,5 @@ export const clineProfile = createProfile({
|
|||||||
docsUrl: 'docs.cline.bot',
|
docsUrl: 'docs.cline.bot',
|
||||||
profileDir: '.clinerules',
|
profileDir: '.clinerules',
|
||||||
rulesDir: '.clinerules',
|
rulesDir: '.clinerules',
|
||||||
mcpConfig: false,
|
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'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,59 +1,18 @@
|
|||||||
// Codex profile for rule-transformer
|
// Codex profile for rule-transformer
|
||||||
import path from 'path';
|
import { createProfile } from './base-profile.js';
|
||||||
import fs from 'fs';
|
|
||||||
import { isSilentMode, log } from '../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
// Lifecycle functions for Codex profile
|
// Create and export codex profile using the base factory
|
||||||
function onAddRulesProfile(targetDir, assetsDir) {
|
export const codexProfile = createProfile({
|
||||||
// Use the provided assets directory to find the source file
|
name: 'codex',
|
||||||
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',
|
|
||||||
displayName: 'Codex',
|
displayName: 'Codex',
|
||||||
|
url: 'codex.ai',
|
||||||
|
docsUrl: 'platform.openai.com/docs/codex',
|
||||||
profileDir: '.', // Root directory
|
profileDir: '.', // Root directory
|
||||||
rulesDir: '.', // No rules directory needed
|
rulesDir: '.', // No specific rules directory needed
|
||||||
mcpConfig: false, // No MCP config needed
|
mcpConfig: false,
|
||||||
mcpConfigName: null,
|
mcpConfigName: null,
|
||||||
mcpConfigPath: null,
|
includeDefaultRules: false,
|
||||||
conversionConfig: {},
|
fileMap: {
|
||||||
fileMap: {},
|
'AGENTS.md': 'AGENTS.md'
|
||||||
globalReplacements: [],
|
}
|
||||||
getTargetRuleFilename,
|
});
|
||||||
onAddRulesProfile,
|
|
||||||
onRemoveRulesProfile,
|
|
||||||
onPostConvertRulesProfile
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -7,15 +7,6 @@ export const cursorProfile = createProfile({
|
|||||||
displayName: 'Cursor',
|
displayName: 'Cursor',
|
||||||
url: 'cursor.so',
|
url: 'cursor.so',
|
||||||
docsUrl: 'docs.cursor.com',
|
docsUrl: 'docs.cursor.com',
|
||||||
profileDir: '.cursor',
|
|
||||||
rulesDir: '.cursor/rules',
|
|
||||||
mcpConfig: true,
|
|
||||||
mcpConfigName: 'mcp.json',
|
|
||||||
fileExtension: '.mdc',
|
|
||||||
targetExtension: '.mdc', // Cursor keeps .mdc extension
|
targetExtension: '.mdc', // Cursor keeps .mdc extension
|
||||||
toolMappings: COMMON_TOOL_MAPPINGS.STANDARD,
|
supportsRulesSubdirectories: true
|
||||||
supportsRulesSubdirectories: true,
|
|
||||||
customFileMap: {
|
|
||||||
'cursor_rules.mdc': 'cursor_rules.mdc' // Keep the same name for cursor
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
17
src/profiles/gemini.js
Normal file
17
src/profiles/gemini.js
Normal file
@@ -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'
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -3,6 +3,7 @@ export { claudeProfile } from './claude.js';
|
|||||||
export { clineProfile } from './cline.js';
|
export { clineProfile } from './cline.js';
|
||||||
export { codexProfile } from './codex.js';
|
export { codexProfile } from './codex.js';
|
||||||
export { cursorProfile } from './cursor.js';
|
export { cursorProfile } from './cursor.js';
|
||||||
|
export { geminiProfile } from './gemini.js';
|
||||||
export { rooProfile } from './roo.js';
|
export { rooProfile } from './roo.js';
|
||||||
export { traeProfile } from './trae.js';
|
export { traeProfile } from './trae.js';
|
||||||
export { vscodeProfile } from './vscode.js';
|
export { vscodeProfile } from './vscode.js';
|
||||||
|
|||||||
@@ -110,16 +110,7 @@ export const rooProfile = createProfile({
|
|||||||
displayName: 'Roo Code',
|
displayName: 'Roo Code',
|
||||||
url: 'roocode.com',
|
url: 'roocode.com',
|
||||||
docsUrl: 'docs.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,
|
toolMappings: COMMON_TOOL_MAPPINGS.ROO_STYLE,
|
||||||
customFileMap: {
|
|
||||||
'cursor_rules.mdc': 'roo_rules.md'
|
|
||||||
},
|
|
||||||
onAdd: onAddRulesProfile,
|
onAdd: onAddRulesProfile,
|
||||||
onRemove: onRemoveRulesProfile,
|
onRemove: onRemoveRulesProfile,
|
||||||
onPostConvert: onPostConvertRulesProfile
|
onPostConvert: onPostConvertRulesProfile
|
||||||
|
|||||||
@@ -7,11 +7,5 @@ export const traeProfile = createProfile({
|
|||||||
displayName: 'Trae',
|
displayName: 'Trae',
|
||||||
url: 'trae.ai',
|
url: 'trae.ai',
|
||||||
docsUrl: 'docs.trae.ai',
|
docsUrl: 'docs.trae.ai',
|
||||||
profileDir: '.trae',
|
mcpConfig: false
|
||||||
rulesDir: '.trae/rules',
|
|
||||||
mcpConfig: false,
|
|
||||||
mcpConfigName: 'trae_mcp_settings.json',
|
|
||||||
fileExtension: '.mdc',
|
|
||||||
targetExtension: '.md',
|
|
||||||
toolMappings: COMMON_TOOL_MAPPINGS.STANDARD // Trae uses standard tool names
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,16 +7,7 @@ export const vscodeProfile = createProfile({
|
|||||||
displayName: 'VS Code',
|
displayName: 'VS Code',
|
||||||
url: 'code.visualstudio.com',
|
url: 'code.visualstudio.com',
|
||||||
docsUrl: 'code.visualstudio.com/docs',
|
docsUrl: 'code.visualstudio.com/docs',
|
||||||
profileDir: '.vscode', // MCP config location
|
|
||||||
rulesDir: '.github/instructions', // VS Code instructions 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: [
|
customReplacements: [
|
||||||
// Core VS Code directory structure changes
|
// Core VS Code directory structure changes
|
||||||
{ from: /\.cursor\/rules/g, to: '.github/instructions' },
|
{ from: /\.cursor\/rules/g, to: '.github/instructions' },
|
||||||
|
|||||||
@@ -6,12 +6,5 @@ export const windsurfProfile = createProfile({
|
|||||||
name: 'windsurf',
|
name: 'windsurf',
|
||||||
displayName: 'Windsurf',
|
displayName: 'Windsurf',
|
||||||
url: 'windsurf.com',
|
url: 'windsurf.com',
|
||||||
docsUrl: 'docs.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
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,15 +47,15 @@ export function setupMCPConfiguration(projectRoot, mcpConfigPath) {
|
|||||||
command: 'npx',
|
command: 'npx',
|
||||||
args: ['-y', '--package=task-master-ai', 'task-master-ai'],
|
args: ['-y', '--package=task-master-ai', 'task-master-ai'],
|
||||||
env: {
|
env: {
|
||||||
ANTHROPIC_API_KEY: 'ANTHROPIC_API_KEY_HERE',
|
ANTHROPIC_API_KEY: 'YOUR_ANTHROPIC_API_KEY_HERE',
|
||||||
PERPLEXITY_API_KEY: 'PERPLEXITY_API_KEY_HERE',
|
PERPLEXITY_API_KEY: 'YOUR_PERPLEXITY_API_KEY_HERE',
|
||||||
OPENAI_API_KEY: 'OPENAI_API_KEY_HERE',
|
OPENAI_API_KEY: 'YOUR_OPENAI_KEY_HERE',
|
||||||
GOOGLE_API_KEY: 'GOOGLE_API_KEY_HERE',
|
GOOGLE_API_KEY: 'YOUR_GOOGLE_KEY_HERE',
|
||||||
XAI_API_KEY: 'XAI_API_KEY_HERE',
|
XAI_API_KEY: 'YOUR_XAI_KEY_HERE',
|
||||||
OPENROUTER_API_KEY: 'OPENROUTER_API_KEY_HERE',
|
OPENROUTER_API_KEY: 'YOUR_OPENROUTER_KEY_HERE',
|
||||||
MISTRAL_API_KEY: 'MISTRAL_API_KEY_HERE',
|
MISTRAL_API_KEY: 'YOUR_MISTRAL_KEY_HERE',
|
||||||
AZURE_OPENAI_API_KEY: 'AZURE_OPENAI_API_KEY_HERE',
|
AZURE_OPENAI_API_KEY: 'YOUR_AZURE_KEY_HERE',
|
||||||
OLLAMA_API_KEY: 'OLLAMA_API_KEY_HERE'
|
OLLAMA_API_KEY: 'YOUR_OLLAMA_API_KEY_HERE'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,24 +16,48 @@ import { RULE_PROFILES } from '../constants/profiles.js';
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect which profiles are currently installed in the project
|
* Get the display name for a profile
|
||||||
* @param {string} projectRoot - Project root directory
|
* @param {string} profileName - The profile name
|
||||||
* @returns {string[]} Array of installed profile names
|
* @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) {
|
export function getInstalledProfiles(projectRoot) {
|
||||||
const installedProfiles = [];
|
const installedProfiles = [];
|
||||||
|
|
||||||
for (const profileName of RULE_PROFILES) {
|
for (const profileName of RULE_PROFILES) {
|
||||||
const profileConfig = getRulesProfile(profileName);
|
try {
|
||||||
if (!profileConfig) continue;
|
const profile = getRulesProfile(profileName);
|
||||||
|
const profileDir = path.join(projectRoot, profile.profileDir);
|
||||||
|
|
||||||
// Check if the profile directory exists
|
// Check if profile directory exists (skip root directory check)
|
||||||
const profileDir = path.join(projectRoot, profileConfig.profileDir);
|
if (profile.profileDir === '.' || fs.existsSync(profileDir)) {
|
||||||
const rulesDir = path.join(projectRoot, profileConfig.rulesDir);
|
// Check if any files from the profile's fileMap exist
|
||||||
|
const rulesDir = path.join(projectRoot, profile.rulesDir);
|
||||||
// A profile is considered installed if either the profile dir or rules dir exists
|
if (fs.existsSync(rulesDir)) {
|
||||||
if (fs.existsSync(profileDir) || fs.existsSync(rulesDir)) {
|
const ruleFiles = Object.values(profile.fileMap);
|
||||||
installedProfiles.push(profileName);
|
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} projectRoot - Project root directory
|
||||||
* @param {string[]} profilesToRemove - Array of profile names to remove
|
* @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) {
|
export function wouldRemovalLeaveNoProfiles(projectRoot, profilesToRemove) {
|
||||||
const installedProfiles = getInstalledProfiles(projectRoot);
|
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(
|
const remainingProfiles = installedProfiles.filter(
|
||||||
(profile) => !profilesToRemove.includes(profile)
|
(profile) => !profilesToRemove.includes(profile)
|
||||||
);
|
);
|
||||||
|
return remainingProfiles.length === 0;
|
||||||
return remainingProfiles.length === 0 && installedProfiles.length > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// PROFILE SETUP
|
// 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()
|
// Note: Profile choices are now generated dynamically within runInteractiveProfilesSetup()
|
||||||
// to ensure proper alphabetical sorting and pagination configuration
|
// to ensure proper alphabetical sorting and pagination configuration
|
||||||
|
|
||||||
@@ -86,26 +107,32 @@ export async function runInteractiveProfilesSetup() {
|
|||||||
const displayName = getProfileDisplayName(profileName);
|
const displayName = getProfileDisplayName(profileName);
|
||||||
const profile = getRulesProfile(profileName);
|
const profile = getRulesProfile(profileName);
|
||||||
|
|
||||||
// Determine description based on profile type
|
// Determine description based on profile capabilities
|
||||||
let description;
|
let description;
|
||||||
if (Object.keys(profile.fileMap).length === 0) {
|
const hasRules = Object.keys(profile.fileMap).length > 0;
|
||||||
// Simple profiles (Claude, Codex) - specify the target file
|
const hasMcpConfig = profile.mcpConfig === true;
|
||||||
const targetFileName =
|
|
||||||
profileName === 'claude' ? 'CLAUDE.md' : 'AGENTS.md';
|
if (!profile.includeDefaultRules) {
|
||||||
description = `Integration guide (${targetFileName})`;
|
// Integration guide profiles (claude, codex, gemini) - don't include standard coding rules
|
||||||
} else {
|
if (profileName === 'claude') {
|
||||||
// Full profiles with rules - check if they have MCP config
|
description = 'Integration guide with Task Master slash commands';
|
||||||
const hasMcpConfig = profile.mcpConfig === true;
|
} else if (profileName === 'codex') {
|
||||||
if (hasMcpConfig) {
|
description = 'Comprehensive Task Master integration guide';
|
||||||
// Special case for Roo to mention agent modes
|
} else if (profileName === 'gemini') {
|
||||||
if (profileName === 'roo') {
|
description = 'Integration guide and MCP config';
|
||||||
description = 'Rule profile, MCP config, and agent modes';
|
|
||||||
} else {
|
|
||||||
description = 'Rule profile and MCP config';
|
|
||||||
}
|
|
||||||
} else {
|
} 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 {
|
return {
|
||||||
@@ -170,14 +197,13 @@ export async function runInteractiveProfilesSetup() {
|
|||||||
*/
|
*/
|
||||||
export function generateProfileSummary(profileName, addResult) {
|
export function generateProfileSummary(profileName, addResult) {
|
||||||
const profileConfig = getRulesProfile(profileName);
|
const profileConfig = getRulesProfile(profileName);
|
||||||
const isSimpleProfile = Object.keys(profileConfig.fileMap).length === 0;
|
|
||||||
|
|
||||||
if (isSimpleProfile) {
|
if (!profileConfig.includeDefaultRules) {
|
||||||
// Simple profiles like Claude and Codex only copy AGENTS.md
|
// Integration guide profiles (claude, codex, gemini)
|
||||||
const targetFileName = profileName === 'claude' ? 'CLAUDE.md' : 'AGENTS.md';
|
return `Summary for ${profileName}: Integration guide installed.`;
|
||||||
return `Summary for ${profileName}: Integration guide copied to ${targetFileName}`;
|
|
||||||
} else {
|
} 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
|
* @returns {string} Formatted summary message
|
||||||
*/
|
*/
|
||||||
export function generateProfileRemovalSummary(profileName, removeResult) {
|
export function generateProfileRemovalSummary(profileName, removeResult) {
|
||||||
const profileConfig = getRulesProfile(profileName);
|
|
||||||
const isSimpleProfile = Object.keys(profileConfig.fileMap).length === 0;
|
|
||||||
|
|
||||||
if (removeResult.skipped) {
|
if (removeResult.skipped) {
|
||||||
return `Summary for ${profileName}: Skipped (default or protected files)`;
|
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}`;
|
return `Summary for ${profileName}: Failed to remove - ${removeResult.error}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSimpleProfile) {
|
const profileConfig = getRulesProfile(profileName);
|
||||||
// Simple profiles like Claude and Codex only have an integration guide
|
|
||||||
const targetFileName = profileName === 'claude' ? 'CLAUDE.md' : 'AGENTS.md';
|
if (!profileConfig.includeDefaultRules) {
|
||||||
return `Summary for ${profileName}: Integration guide (${targetFileName}) removed`;
|
// Integration guide profiles (claude, codex, gemini)
|
||||||
|
const baseMessage = `Summary for ${profileName}: Integration guide removed`;
|
||||||
|
if (removeResult.notice) {
|
||||||
|
return `${baseMessage} (${removeResult.notice})`;
|
||||||
|
}
|
||||||
|
return baseMessage;
|
||||||
} else {
|
} else {
|
||||||
// Full profiles have rules directories and potentially MCP configs
|
// Rule profiles with coding guidelines
|
||||||
const baseMessage = `Summary for ${profileName}: Rules directory removed`;
|
const baseMessage = `Summary for ${profileName}: Rule profile removed`;
|
||||||
if (removeResult.notice) {
|
if (removeResult.notice) {
|
||||||
return `${baseMessage} (${removeResult.notice})`;
|
return `${baseMessage} (${removeResult.notice})`;
|
||||||
}
|
}
|
||||||
@@ -220,7 +248,6 @@ export function generateProfileRemovalSummary(profileName, removeResult) {
|
|||||||
*/
|
*/
|
||||||
export function categorizeProfileResults(addResults) {
|
export function categorizeProfileResults(addResults) {
|
||||||
const successfulProfiles = [];
|
const successfulProfiles = [];
|
||||||
const simpleProfiles = [];
|
|
||||||
let totalSuccess = 0;
|
let totalSuccess = 0;
|
||||||
let totalFailed = 0;
|
let totalFailed = 0;
|
||||||
|
|
||||||
@@ -228,22 +255,15 @@ export function categorizeProfileResults(addResults) {
|
|||||||
totalSuccess += r.success;
|
totalSuccess += r.success;
|
||||||
totalFailed += r.failed;
|
totalFailed += r.failed;
|
||||||
|
|
||||||
const profileConfig = getRulesProfile(r.profileName);
|
// All profiles are considered successful if they completed without major errors
|
||||||
const isSimpleProfile = Object.keys(profileConfig.fileMap).length === 0;
|
if (r.success > 0 || r.failed === 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
|
|
||||||
successfulProfiles.push(r.profileName);
|
successfulProfiles.push(r.profileName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
successfulProfiles,
|
successfulProfiles,
|
||||||
simpleProfiles,
|
allSuccessfulProfiles: successfulProfiles,
|
||||||
allSuccessfulProfiles: [...successfulProfiles, ...simpleProfiles],
|
|
||||||
totalSuccess,
|
totalSuccess,
|
||||||
totalFailed
|
totalFailed
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -199,97 +199,130 @@ export function convertRuleToProfileRule(sourcePath, targetPath, profile) {
|
|||||||
* Convert all Cursor rules to profile rules for a specific profile
|
* Convert all Cursor rules to profile rules for a specific profile
|
||||||
*/
|
*/
|
||||||
export function convertAllRulesToProfileRules(projectRoot, 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 __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
const sourceDir = path.join(__dirname, '..', '..', 'assets', 'rules');
|
const sourceDir = path.join(__dirname, '..', '..', 'assets', 'rules');
|
||||||
const targetDir = path.join(projectRoot, profile.rulesDir);
|
const targetDir = path.join(projectRoot, profile.rulesDir);
|
||||||
|
const assetsDir = path.join(__dirname, '..', '..', 'assets');
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let success = 0;
|
let success = 0;
|
||||||
let failed = 0;
|
let failed = 0;
|
||||||
|
|
||||||
// Use fileMap to determine which files to copy
|
// 1. Call onAddRulesProfile first (for pre-processing like copying assets)
|
||||||
const sourceFiles = Object.keys(profile.fileMap);
|
if (typeof profile.onAddRulesProfile === 'function') {
|
||||||
|
|
||||||
for (const sourceFile of sourceFiles) {
|
|
||||||
try {
|
try {
|
||||||
const sourcePath = path.join(sourceDir, sourceFile);
|
profile.onAddRulesProfile(projectRoot, assetsDir);
|
||||||
|
|
||||||
// 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++;
|
|
||||||
|
|
||||||
log(
|
log(
|
||||||
'debug',
|
'debug',
|
||||||
`[Rule Transformer] Converted ${sourceFile} -> ${targetFilename} for ${profile.profileName}`
|
`[Rule Transformer] Called onAddRulesProfile for ${profile.profileName}`
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
failed++;
|
|
||||||
log(
|
log(
|
||||||
'error',
|
'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') {
|
if (typeof profile.onPostConvertRulesProfile === 'function') {
|
||||||
const assetsDir = path.join(__dirname, '..', '..', 'assets');
|
try {
|
||||||
profile.onPostConvertRulesProfile(projectRoot, assetsDir);
|
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 {
|
try {
|
||||||
// Handle simple profiles (Claude, Codex) that just copy files to root
|
// 1. Call onRemoveRulesProfile first (for custom cleanup like removing assets)
|
||||||
const isSimpleProfile = Object.keys(profile.fileMap).length === 0;
|
if (typeof profile.onRemoveRulesProfile === 'function') {
|
||||||
|
try {
|
||||||
if (isSimpleProfile) {
|
|
||||||
// For simple profiles, just call their removal hook and return
|
|
||||||
if (typeof profile.onRemoveRulesProfile === 'function') {
|
|
||||||
profile.onRemoveRulesProfile(projectRoot);
|
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)
|
// 2. Remove fileMap-based files (if any)
|
||||||
if (!fs.existsSync(profileDir)) {
|
const sourceFiles = Object.keys(profile.fileMap);
|
||||||
result.success = true;
|
if (sourceFiles.length > 0) {
|
||||||
result.skipped = true;
|
// Check if profile directory exists at all (for full profiles)
|
||||||
log(
|
if (!fs.existsSync(profileDir)) {
|
||||||
'debug',
|
result.success = true;
|
||||||
`[Rule Transformer] Profile directory does not exist: ${profileDir}`
|
result.skipped = true;
|
||||||
);
|
log(
|
||||||
return result;
|
'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;
|
||||||
let hasOtherRulesFiles = false;
|
|
||||||
if (fs.existsSync(targetDir)) {
|
|
||||||
const taskmasterFiles = Object.values(profile.fileMap);
|
|
||||||
const removedFiles = [];
|
|
||||||
|
|
||||||
// Helper function to recursively check and remove Task Master files
|
if (fs.existsSync(targetDir)) {
|
||||||
function processDirectory(dirPath, relativePath = '') {
|
// Get list of files we're responsible for
|
||||||
const items = fs.readdirSync(dirPath);
|
const taskMasterFiles = sourceFiles.map(
|
||||||
|
(sourceFile) => profile.fileMap[sourceFile]
|
||||||
|
);
|
||||||
|
|
||||||
for (const item of items) {
|
// Get all files in the rules directory
|
||||||
const itemPath = path.join(dirPath, item);
|
const allFiles = fs.readdirSync(targetDir, { recursive: true });
|
||||||
const relativeItemPath = relativePath
|
const allFilePaths = allFiles
|
||||||
? path.join(relativePath, item)
|
.filter((file) => {
|
||||||
: item;
|
const fullPath = path.join(targetDir, file);
|
||||||
const stat = fs.statSync(itemPath);
|
return fs.statSync(fullPath).isFile();
|
||||||
|
})
|
||||||
|
.map((file) => file.toString()); // Ensure it's a string
|
||||||
|
|
||||||
if (stat.isDirectory()) {
|
// Remove only Task Master files
|
||||||
// Recursively process subdirectory
|
for (const taskMasterFile of taskMasterFiles) {
|
||||||
processDirectory(itemPath, relativeItemPath);
|
const filePath = path.join(targetDir, taskMasterFile);
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
// Check if directory is empty after processing and remove if so
|
|
||||||
try {
|
try {
|
||||||
const remainingItems = fs.readdirSync(itemPath);
|
fs.rmSync(filePath, { force: true });
|
||||||
if (remainingItems.length === 0) {
|
result.filesRemoved.push(taskMasterFile);
|
||||||
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);
|
|
||||||
log(
|
log(
|
||||||
'debug',
|
'debug',
|
||||||
`[Rule Transformer] Removed Task Master file: ${relativeItemPath}`
|
`[Rule Transformer] Removed Task Master file: ${taskMasterFile}`
|
||||||
);
|
);
|
||||||
} else {
|
} catch (error) {
|
||||||
// This is not a Task Master file, leave it
|
|
||||||
hasOtherRulesFiles = true;
|
|
||||||
log(
|
log(
|
||||||
'debug',
|
'error',
|
||||||
`[Rule Transformer] Preserved existing file: ${relativeItemPath}`
|
`[Rule Transformer] Failed to remove ${taskMasterFile}: ${error.message}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Process the rules directory recursively
|
// Check for other (non-Task Master) files
|
||||||
processDirectory(targetDir);
|
const remainingFiles = allFilePaths.filter(
|
||||||
|
(file) => !taskMasterFiles.includes(file)
|
||||||
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}`
|
|
||||||
);
|
);
|
||||||
} 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
|
hasOtherRulesFiles = remainingFiles.length > 0;
|
||||||
if (profile.mcpConfig !== false) {
|
|
||||||
result.mcpResult = removeTaskMasterMCPConfiguration(
|
// Remove empty directories or note preserved files
|
||||||
projectRoot,
|
if (remainingFiles.length === 0) {
|
||||||
profile.mcpConfigPath
|
fs.rmSync(targetDir, { recursive: true, force: true });
|
||||||
);
|
log(
|
||||||
if (result.mcpResult.hasOtherServers) {
|
'debug',
|
||||||
if (!result.notice) {
|
`[Rule Transformer] Removed empty rules directory: ${targetDir}`
|
||||||
result.notice = 'Preserved other MCP server configurations';
|
);
|
||||||
} else {
|
} else if (hasOtherRulesFiles) {
|
||||||
result.notice += '; preserved other MCP server configurations';
|
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)
|
// 3. Handle MCP configuration - only remove Task Master, preserve other servers
|
||||||
if (typeof profile.onRemoveRulesProfile === 'function') {
|
if (profile.mcpConfig !== false) {
|
||||||
profile.onRemoveRulesProfile(projectRoot);
|
try {
|
||||||
}
|
result.mcpResult = removeTaskMasterMCPConfiguration(
|
||||||
|
projectRoot,
|
||||||
// 4. Only remove profile directory if:
|
profile.mcpConfigPath
|
||||||
// - It's completely empty after all operations, AND
|
);
|
||||||
// - All rules removed were Task Master rules (no existing rules preserved), AND
|
if (result.mcpResult.hasOtherServers) {
|
||||||
// - MCP config was completely deleted (not just Task Master removed), AND
|
if (!result.notice) {
|
||||||
// - No other files or folders exist in the profile directory
|
result.notice = 'Preserved other MCP server configurations';
|
||||||
if (fs.existsSync(profileDir)) {
|
} else {
|
||||||
const remaining = fs.readdirSync(profileDir);
|
result.notice += '; preserved other MCP server configurations';
|
||||||
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;
|
|
||||||
log(
|
log(
|
||||||
'debug',
|
'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 {
|
} catch (error) {
|
||||||
// Determine what was preserved and why
|
log(
|
||||||
const preservationReasons = [];
|
'error',
|
||||||
if (hasOtherFilesOrFolders) {
|
`[Rule Transformer] MCP cleanup failed for ${profile.profileName}: ${error.message}`
|
||||||
preservationReasons.push(
|
);
|
||||||
`${remaining.length} existing files/folders`
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
} else if (remainingContents.length > 0) {
|
||||||
preservationReasons.push('existing rule files');
|
// Profile directory has remaining files/folders, add notice
|
||||||
}
|
const preservedNotice = `Preserved ${remainingContents.length} existing files/folders in ${profile.profileDir}`;
|
||||||
if (result.mcpResult?.hasOtherServers) {
|
|
||||||
preservationReasons.push('other MCP server configurations');
|
|
||||||
}
|
|
||||||
|
|
||||||
const preservationMessage = `Preserved ${preservationReasons.join(', ')} in ${profile.profileDir}`;
|
|
||||||
|
|
||||||
if (!result.notice) {
|
if (!result.notice) {
|
||||||
result.notice = preservationMessage;
|
result.notice = preservedNotice;
|
||||||
} else if (!result.notice.includes('Preserved')) {
|
} else {
|
||||||
result.notice += `; ${preservationMessage.toLowerCase()}`;
|
result.notice += `; ${preservedNotice.toLowerCase()}`;
|
||||||
}
|
}
|
||||||
|
log('info', `[Rule Transformer] ${preservedNotice}`);
|
||||||
log('info', `[Rule Transformer] ${preservationMessage}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { claudeProfile } from '../../../src/profiles/claude.js';
|
||||||
|
|
||||||
describe('Claude Profile Initialization Functionality', () => {
|
describe('Claude Profile Initialization Functionality', () => {
|
||||||
let claudeProfileContent;
|
let claudeProfileContent;
|
||||||
@@ -14,23 +15,25 @@ describe('Claude Profile Initialization Functionality', () => {
|
|||||||
claudeProfileContent = fs.readFileSync(claudeJsPath, 'utf8');
|
claudeProfileContent = fs.readFileSync(claudeJsPath, 'utf8');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('claude.js is a simple profile with correct configuration', () => {
|
test('claude.js has correct asset-only profile configuration', () => {
|
||||||
expect(claudeProfileContent).toContain("profileName: 'claude'");
|
// Check for explicit, non-default values in the source file
|
||||||
|
expect(claudeProfileContent).toContain("name: 'claude'");
|
||||||
expect(claudeProfileContent).toContain("displayName: 'Claude Code'");
|
expect(claudeProfileContent).toContain("displayName: 'Claude Code'");
|
||||||
expect(claudeProfileContent).toContain("profileDir: '.'");
|
expect(claudeProfileContent).toContain("profileDir: '.'"); // non-default
|
||||||
expect(claudeProfileContent).toContain("rulesDir: '.'");
|
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', () => {
|
// Check the final computed properties on the profile object
|
||||||
expect(claudeProfileContent).toContain('mcpConfig: false');
|
expect(claudeProfile.profileName).toBe('claude');
|
||||||
expect(claudeProfileContent).toContain('mcpConfigName: null');
|
expect(claudeProfile.displayName).toBe('Claude Code');
|
||||||
expect(claudeProfileContent).toContain('mcpConfigPath: null');
|
expect(claudeProfile.profileDir).toBe('.');
|
||||||
});
|
expect(claudeProfile.rulesDir).toBe('.');
|
||||||
|
expect(claudeProfile.mcpConfig).toBe(false);
|
||||||
test('claude.js has empty file map (simple profile)', () => {
|
expect(claudeProfile.mcpConfigName).toBe(null); // computed
|
||||||
expect(claudeProfileContent).toContain('fileMap: {}');
|
expect(claudeProfile.includeDefaultRules).toBe(false);
|
||||||
expect(claudeProfileContent).toContain('conversionConfig: {}');
|
expect(claudeProfile.fileMap['AGENTS.md']).toBe('CLAUDE.md');
|
||||||
expect(claudeProfileContent).toContain('globalReplacements: []');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('claude.js has lifecycle functions for file management', () => {
|
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', () => {
|
test('claude.js handles .claude directory in lifecycle functions', () => {
|
||||||
expect(claudeProfileContent).toContain("'AGENTS.md'");
|
expect(claudeProfileContent).toContain('.claude');
|
||||||
expect(claudeProfileContent).toContain("'CLAUDE.md'");
|
expect(claudeProfileContent).toContain('copyRecursiveSync');
|
||||||
expect(claudeProfileContent).toContain('copyFileSync');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('claude.js has proper error handling', () => {
|
test('claude.js has proper error handling in lifecycle functions', () => {
|
||||||
expect(claudeProfileContent).toContain('try {');
|
expect(claudeProfileContent).toContain('try {');
|
||||||
expect(claudeProfileContent).toContain('} catch (err) {');
|
expect(claudeProfileContent).toContain('} catch (err) {');
|
||||||
expect(claudeProfileContent).toContain("log('error'");
|
expect(claudeProfileContent).toContain("log('error'");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { clineProfile } from '../../../src/profiles/cline.js';
|
||||||
|
|
||||||
describe('Cline Profile Initialization Functionality', () => {
|
describe('Cline Profile Initialization Functionality', () => {
|
||||||
let clineProfileContent;
|
let clineProfileContent;
|
||||||
@@ -10,39 +11,48 @@ describe('Cline Profile Initialization Functionality', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('cline.js uses factory pattern with correct configuration', () => {
|
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("name: 'cline'");
|
||||||
expect(clineProfileContent).toContain("displayName: 'Cline'");
|
expect(clineProfileContent).toContain("displayName: 'Cline'");
|
||||||
expect(clineProfileContent).toContain("rulesDir: '.clinerules'");
|
expect(clineProfileContent).toContain("profileDir: '.clinerules'"); // non-default
|
||||||
expect(clineProfileContent).toContain("profileDir: '.clinerules'");
|
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', () => {
|
test('cline.js configures .mdc to .md extension mapping', () => {
|
||||||
expect(clineProfileContent).toContain("fileExtension: '.mdc'");
|
// Check that the profile object has the correct file mapping behavior (cline converts to .md)
|
||||||
expect(clineProfileContent).toContain("targetExtension: '.md'");
|
expect(clineProfile.fileMap['rules/cursor_rules.mdc']).toBe(
|
||||||
});
|
'cline_rules.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'"
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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', () => {
|
test('cline.js has custom file mapping for cursor_rules.mdc', () => {
|
||||||
expect(clineProfileContent).toContain('customFileMap:');
|
// Check actual behavior - cline gets default rule files
|
||||||
expect(clineProfileContent).toContain(
|
expect(Object.keys(clineProfile.fileMap)).toContain(
|
||||||
"'cursor_rules.mdc': 'cline_rules.md'"
|
'rules/cursor_rules.mdc'
|
||||||
|
);
|
||||||
|
expect(clineProfile.fileMap['rules/cursor_rules.mdc']).toBe(
|
||||||
|
'cline_rules.md'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { codexProfile } from '../../../src/profiles/codex.js';
|
||||||
|
|
||||||
describe('Codex Profile Initialization Functionality', () => {
|
describe('Codex Profile Initialization Functionality', () => {
|
||||||
let codexProfileContent;
|
let codexProfileContent;
|
||||||
@@ -9,46 +10,41 @@ describe('Codex Profile Initialization Functionality', () => {
|
|||||||
codexProfileContent = fs.readFileSync(codexJsPath, 'utf8');
|
codexProfileContent = fs.readFileSync(codexJsPath, 'utf8');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('codex.js is a simple profile with correct configuration', () => {
|
test('codex.js has correct asset-only profile configuration', () => {
|
||||||
expect(codexProfileContent).toContain("profileName: 'codex'");
|
// Check for explicit, non-default values in the source file
|
||||||
|
expect(codexProfileContent).toContain("name: 'codex'");
|
||||||
expect(codexProfileContent).toContain("displayName: 'Codex'");
|
expect(codexProfileContent).toContain("displayName: 'Codex'");
|
||||||
expect(codexProfileContent).toContain("profileDir: '.'");
|
expect(codexProfileContent).toContain("profileDir: '.'"); // non-default
|
||||||
expect(codexProfileContent).toContain("rulesDir: '.'");
|
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', () => {
|
test('codex.js has no lifecycle functions', () => {
|
||||||
expect(codexProfileContent).toContain('mcpConfig: false');
|
// Codex has been simplified - no lifecycle functions
|
||||||
expect(codexProfileContent).toContain('mcpConfigName: null');
|
expect(codexProfileContent).not.toContain('function onAddRulesProfile');
|
||||||
expect(codexProfileContent).toContain('mcpConfigPath: null');
|
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)', () => {
|
test('codex.js has minimal implementation', () => {
|
||||||
expect(codexProfileContent).toContain('fileMap: {}');
|
// Should just use createProfile factory
|
||||||
expect(codexProfileContent).toContain('conversionConfig: {}');
|
expect(codexProfileContent).toContain('createProfile({');
|
||||||
expect(codexProfileContent).toContain('globalReplacements: []');
|
expect(codexProfileContent).toContain("name: 'codex'");
|
||||||
});
|
expect(codexProfileContent).toContain("'AGENTS.md': 'AGENTS.md'");
|
||||||
|
|
||||||
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');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { cursorProfile } from '../../../src/profiles/cursor.js';
|
||||||
|
|
||||||
describe('Cursor Profile Initialization Functionality', () => {
|
describe('Cursor Profile Initialization Functionality', () => {
|
||||||
let cursorProfileContent;
|
let cursorProfileContent;
|
||||||
@@ -15,30 +16,42 @@ describe('Cursor Profile Initialization Functionality', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('cursor.js uses factory pattern with correct configuration', () => {
|
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("name: 'cursor'");
|
||||||
expect(cursorProfileContent).toContain("displayName: 'Cursor'");
|
expect(cursorProfileContent).toContain("displayName: 'Cursor'");
|
||||||
expect(cursorProfileContent).toContain("rulesDir: '.cursor/rules'");
|
expect(cursorProfileContent).toContain("url: 'cursor.so'");
|
||||||
expect(cursorProfileContent).toContain("profileDir: '.cursor'");
|
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', () => {
|
test('cursor.js preserves .mdc extension in both input and output', () => {
|
||||||
expect(cursorProfileContent).toContain("fileExtension: '.mdc'");
|
// Check that the profile object has the correct file mapping behavior (cursor keeps .mdc)
|
||||||
expect(cursorProfileContent).toContain("targetExtension: '.mdc'");
|
expect(cursorProfile.fileMap['rules/cursor_rules.mdc']).toBe(
|
||||||
// Should preserve cursor_rules.mdc filename
|
'cursor_rules.mdc'
|
||||||
expect(cursorProfileContent).toContain(
|
|
||||||
"'cursor_rules.mdc': '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)', () => {
|
test('cursor.js uses standard tool mappings (no tool renaming)', () => {
|
||||||
expect(cursorProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD');
|
// Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD)
|
||||||
// Should not contain custom tool mappings since cursor keeps original names
|
// This verifies the architectural pattern: no custom toolMappings = standard tool names
|
||||||
expect(cursorProfileContent).not.toContain('edit_file');
|
expect(cursorProfileContent).not.toContain('toolMappings:');
|
||||||
expect(cursorProfileContent).not.toContain('apply_diff');
|
expect(cursorProfileContent).not.toContain('apply_diff');
|
||||||
});
|
expect(cursorProfileContent).not.toContain('search_files');
|
||||||
|
|
||||||
test('cursor.js contains correct URL configuration', () => {
|
// Verify the result: default mappings means tools keep their original names
|
||||||
expect(cursorProfileContent).toContain("url: 'cursor.so'");
|
expect(cursorProfile.conversionConfig.toolNames.edit_file).toBe(
|
||||||
expect(cursorProfileContent).toContain("docsUrl: 'docs.cursor.com'");
|
'edit_file'
|
||||||
|
);
|
||||||
|
expect(cursorProfile.conversionConfig.toolNames.search).toBe('search');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
72
tests/integration/profiles/gemini-init-functionality.test.js
Normal file
72
tests/integration/profiles/gemini-init-functionality.test.js
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { jest } from '@jest/globals';
|
import { jest } from '@jest/globals';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
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', () => {
|
describe('Roo Profile Initialization Functionality', () => {
|
||||||
let rooProfileContent;
|
let rooProfileContent;
|
||||||
@@ -11,6 +13,33 @@ describe('Roo Profile Initialization Functionality', () => {
|
|||||||
rooProfileContent = fs.readFileSync(rooJsPath, 'utf8');
|
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', () => {
|
test('roo.js profile ensures Roo directory structure via onAddRulesProfile', () => {
|
||||||
// Check if onAddRulesProfile function exists
|
// Check if onAddRulesProfile function exists
|
||||||
expect(rooProfileContent).toContain(
|
expect(rooProfileContent).toContain(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { traeProfile } from '../../../src/profiles/trae.js';
|
||||||
|
|
||||||
describe('Trae Profile Initialization Functionality', () => {
|
describe('Trae Profile Initialization Functionality', () => {
|
||||||
let traeProfileContent;
|
let traeProfileContent;
|
||||||
@@ -10,32 +11,36 @@ describe('Trae Profile Initialization Functionality', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('trae.js uses factory pattern with correct configuration', () => {
|
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("name: 'trae'");
|
||||||
expect(traeProfileContent).toContain("displayName: 'Trae'");
|
expect(traeProfileContent).toContain("displayName: 'Trae'");
|
||||||
expect(traeProfileContent).toContain("rulesDir: '.trae/rules'");
|
expect(traeProfileContent).toContain("url: 'trae.ai'");
|
||||||
expect(traeProfileContent).toContain("profileDir: '.trae'");
|
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', () => {
|
test('trae.js configures .mdc to .md extension mapping', () => {
|
||||||
expect(traeProfileContent).toContain("fileExtension: '.mdc'");
|
// Check that the profile object has the correct file mapping behavior (trae converts to .md)
|
||||||
expect(traeProfileContent).toContain("targetExtension: '.md'");
|
expect(traeProfile.fileMap['rules/cursor_rules.mdc']).toBe('trae_rules.md');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('trae.js uses standard tool mappings', () => {
|
test('trae.js uses standard tool mappings', () => {
|
||||||
expect(traeProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD');
|
// Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD)
|
||||||
// Should contain comment about standard tool names
|
// This verifies the architectural pattern: no custom toolMappings = standard tool names
|
||||||
expect(traeProfileContent).toContain('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', () => {
|
// Verify the result: default mappings means tools keep their original names
|
||||||
expect(traeProfileContent).toContain("url: 'trae.ai'");
|
expect(traeProfile.conversionConfig.toolNames.edit_file).toBe('edit_file');
|
||||||
expect(traeProfileContent).toContain("docsUrl: 'docs.trae.ai'");
|
expect(traeProfile.conversionConfig.toolNames.search).toBe('search');
|
||||||
});
|
|
||||||
|
|
||||||
test('trae.js has MCP configuration disabled', () => {
|
|
||||||
expect(traeProfileContent).toContain('mcpConfig: false');
|
|
||||||
expect(traeProfileContent).toContain(
|
|
||||||
"mcpConfigName: 'trae_mcp_settings.json'"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
58
tests/integration/profiles/vscode-init-functionality.test.js
Normal file
58
tests/integration/profiles/vscode-init-functionality.test.js
Normal file
@@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { windsurfProfile } from '../../../src/profiles/windsurf.js';
|
||||||
|
|
||||||
describe('Windsurf Profile Initialization Functionality', () => {
|
describe('Windsurf Profile Initialization Functionality', () => {
|
||||||
let windsurfProfileContent;
|
let windsurfProfileContent;
|
||||||
@@ -15,25 +16,39 @@ describe('Windsurf Profile Initialization Functionality', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('windsurf.js uses factory pattern with correct configuration', () => {
|
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("name: 'windsurf'");
|
||||||
expect(windsurfProfileContent).toContain("displayName: 'Windsurf'");
|
expect(windsurfProfileContent).toContain("displayName: 'Windsurf'");
|
||||||
expect(windsurfProfileContent).toContain("rulesDir: '.windsurf/rules'");
|
expect(windsurfProfileContent).toContain("url: 'windsurf.com'");
|
||||||
expect(windsurfProfileContent).toContain("profileDir: '.windsurf'");
|
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', () => {
|
test('windsurf.js configures .mdc to .md extension mapping', () => {
|
||||||
expect(windsurfProfileContent).toContain("fileExtension: '.mdc'");
|
// Check that the profile object has the correct file mapping behavior (windsurf converts to .md)
|
||||||
expect(windsurfProfileContent).toContain("targetExtension: '.md'");
|
expect(windsurfProfile.fileMap['rules/cursor_rules.mdc']).toBe(
|
||||||
|
'windsurf_rules.md'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('windsurf.js uses standard tool mappings', () => {
|
test('windsurf.js uses standard tool mappings', () => {
|
||||||
expect(windsurfProfileContent).toContain('COMMON_TOOL_MAPPINGS.STANDARD');
|
// Check that the profile uses default tool mappings (equivalent to COMMON_TOOL_MAPPINGS.STANDARD)
|
||||||
// Should contain comment about standard tool names
|
// This verifies the architectural pattern: no custom toolMappings = standard tool names
|
||||||
expect(windsurfProfileContent).toContain('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', () => {
|
// Verify the result: default mappings means tools keep their original names
|
||||||
expect(windsurfProfileContent).toContain("url: 'windsurf.com'");
|
expect(windsurfProfile.conversionConfig.toolNames.edit_file).toBe(
|
||||||
expect(windsurfProfileContent).toContain("docsUrl: 'docs.windsurf.com'");
|
'edit_file'
|
||||||
|
);
|
||||||
|
expect(windsurfProfile.conversionConfig.toolNames.search).toBe('search');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -372,9 +372,7 @@ describe('rules command', () => {
|
|||||||
expect.stringMatching(/removing rules for profile: roo/i)
|
expect.stringMatching(/removing rules for profile: roo/i)
|
||||||
);
|
);
|
||||||
expect(mockConsoleLog).toHaveBeenCalledWith(
|
expect(mockConsoleLog).toHaveBeenCalledWith(
|
||||||
expect.stringMatching(
|
expect.stringMatching(/Summary for roo: Rule profile removed/i)
|
||||||
/Summary for roo: (Rules directory removed|Skipped \(default or protected files\))/i
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
// Should not exit with error
|
// Should not exit with error
|
||||||
expect(mockExit).not.toHaveBeenCalledWith(1);
|
expect(mockExit).not.toHaveBeenCalledWith(1);
|
||||||
|
|||||||
156
tests/unit/profiles/gemini-integration.test.js
Normal file
156
tests/unit/profiles/gemini-integration.test.js
Normal file
@@ -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'));
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -8,8 +8,8 @@ describe('MCP Configuration Validation', () => {
|
|||||||
cline: {
|
cline: {
|
||||||
shouldHaveMcp: false,
|
shouldHaveMcp: false,
|
||||||
expectedDir: '.clinerules',
|
expectedDir: '.clinerules',
|
||||||
expectedConfigName: 'cline_mcp_settings.json',
|
expectedConfigName: null,
|
||||||
expectedPath: '.clinerules/cline_mcp_settings.json'
|
expectedPath: null
|
||||||
},
|
},
|
||||||
cursor: {
|
cursor: {
|
||||||
shouldHaveMcp: true,
|
shouldHaveMcp: true,
|
||||||
@@ -17,6 +17,12 @@ describe('MCP Configuration Validation', () => {
|
|||||||
expectedConfigName: 'mcp.json',
|
expectedConfigName: 'mcp.json',
|
||||||
expectedPath: '.cursor/mcp.json'
|
expectedPath: '.cursor/mcp.json'
|
||||||
},
|
},
|
||||||
|
gemini: {
|
||||||
|
shouldHaveMcp: true,
|
||||||
|
expectedDir: '.gemini',
|
||||||
|
expectedConfigName: 'settings.json',
|
||||||
|
expectedPath: '.gemini/settings.json'
|
||||||
|
},
|
||||||
roo: {
|
roo: {
|
||||||
shouldHaveMcp: true,
|
shouldHaveMcp: true,
|
||||||
expectedDir: '.roo',
|
expectedDir: '.roo',
|
||||||
@@ -26,8 +32,8 @@ describe('MCP Configuration Validation', () => {
|
|||||||
trae: {
|
trae: {
|
||||||
shouldHaveMcp: false,
|
shouldHaveMcp: false,
|
||||||
expectedDir: '.trae',
|
expectedDir: '.trae',
|
||||||
expectedConfigName: 'trae_mcp_settings.json',
|
expectedConfigName: null,
|
||||||
expectedPath: '.trae/trae_mcp_settings.json'
|
expectedPath: null
|
||||||
},
|
},
|
||||||
vscode: {
|
vscode: {
|
||||||
shouldHaveMcp: true,
|
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');
|
const clineProfile = getRulesProfile('cline');
|
||||||
expect(clineProfile.mcpConfigName).toBe('cline_mcp_settings.json');
|
expect(clineProfile.mcpConfigName).toBe(null);
|
||||||
|
|
||||||
const traeProfile = getRulesProfile('trae');
|
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', () => {
|
describe('Profile Directory Structure', () => {
|
||||||
test('should ensure each profile has a unique directory', () => {
|
test('should ensure each profile has a unique directory', () => {
|
||||||
const profileDirs = new Set();
|
const profileDirs = new Set();
|
||||||
// Simple profiles that use root directory (can share the same directory)
|
// Profiles that use root directory (can share the same directory)
|
||||||
const simpleProfiles = ['claude', 'codex'];
|
const rootProfiles = ['claude', 'codex', 'gemini'];
|
||||||
|
|
||||||
RULE_PROFILES.forEach((profileName) => {
|
RULE_PROFILES.forEach((profileName) => {
|
||||||
const profile = getRulesProfile(profileName);
|
const profile = getRulesProfile(profileName);
|
||||||
|
|
||||||
// Simple profiles can share the root directory
|
// Root profiles can share the root directory for rules
|
||||||
if (simpleProfiles.includes(profileName)) {
|
if (rootProfiles.includes(profileName) && profile.rulesDir === '.') {
|
||||||
expect(profile.profileDir).toBe('.');
|
expect(profile.rulesDir).toBe('.');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Full profiles should have unique directories
|
// Profile directories should be unique (except for root profiles)
|
||||||
expect(profileDirs.has(profile.profileDir)).toBe(false);
|
if (!rootProfiles.includes(profileName) || profile.profileDir !== '.') {
|
||||||
profileDirs.add(profile.profileDir);
|
expect(profileDirs.has(profile.profileDir)).toBe(false);
|
||||||
|
profileDirs.add(profile.profileDir);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should ensure profile directories follow expected naming convention', () => {
|
test('should ensure profile directories follow expected naming convention', () => {
|
||||||
// Simple profiles that use root directory
|
// Profiles that use root directory for rules
|
||||||
const simpleProfiles = ['claude', 'codex'];
|
const rootRulesProfiles = ['claude', 'codex', 'gemini'];
|
||||||
|
|
||||||
RULE_PROFILES.forEach((profileName) => {
|
RULE_PROFILES.forEach((profileName) => {
|
||||||
const profile = getRulesProfile(profileName);
|
const profile = getRulesProfile(profileName);
|
||||||
|
|
||||||
// Simple profiles use root directory
|
// Some profiles use root directory for rules
|
||||||
if (simpleProfiles.includes(profileName)) {
|
if (
|
||||||
expect(profile.profileDir).toBe('.');
|
rootRulesProfiles.includes(profileName) &&
|
||||||
return;
|
profile.rulesDir === '.'
|
||||||
|
) {
|
||||||
|
expect(profile.rulesDir).toBe('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Full profiles should follow the .name pattern
|
// Profile directories (not rules directories) should follow the .name pattern
|
||||||
expect(profile.profileDir).toMatch(/^\.[\w-]+$/);
|
// 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('cursor');
|
||||||
|
expect(mcpEnabledProfiles).toContain('gemini');
|
||||||
expect(mcpEnabledProfiles).toContain('roo');
|
expect(mcpEnabledProfiles).toContain('roo');
|
||||||
expect(mcpEnabledProfiles).toContain('vscode');
|
expect(mcpEnabledProfiles).toContain('vscode');
|
||||||
expect(mcpEnabledProfiles).toContain('windsurf');
|
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();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
70
tests/unit/profiles/rule-transformer-gemini.test.js
Normal file
70
tests/unit/profiles/rule-transformer-gemini.test.js
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -17,6 +17,7 @@ describe('Rule Transformer - General', () => {
|
|||||||
'cline',
|
'cline',
|
||||||
'codex',
|
'codex',
|
||||||
'cursor',
|
'cursor',
|
||||||
|
'gemini',
|
||||||
'roo',
|
'roo',
|
||||||
'trae',
|
'trae',
|
||||||
'vscode',
|
'vscode',
|
||||||
@@ -55,9 +56,6 @@ describe('Rule Transformer - General', () => {
|
|||||||
|
|
||||||
describe('Profile Structure', () => {
|
describe('Profile Structure', () => {
|
||||||
it('should have all required properties for each profile', () => {
|
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) => {
|
RULE_PROFILES.forEach((profile) => {
|
||||||
const profileConfig = getRulesProfile(profile);
|
const profileConfig = getRulesProfile(profile);
|
||||||
|
|
||||||
@@ -68,50 +66,50 @@ describe('Rule Transformer - General', () => {
|
|||||||
expect(profileConfig).toHaveProperty('rulesDir');
|
expect(profileConfig).toHaveProperty('rulesDir');
|
||||||
expect(profileConfig).toHaveProperty('profileDir');
|
expect(profileConfig).toHaveProperty('profileDir');
|
||||||
|
|
||||||
// Simple profiles have minimal structure
|
// All profiles should have conversionConfig and fileMap objects
|
||||||
if (simpleProfiles.includes(profile)) {
|
expect(typeof profileConfig.conversionConfig).toBe('object');
|
||||||
// For simple profiles, conversionConfig and fileMap can be empty
|
expect(typeof profileConfig.fileMap).toBe('object');
|
||||||
expect(typeof profileConfig.conversionConfig).toBe('object');
|
|
||||||
expect(typeof profileConfig.fileMap).toBe('object');
|
// Check that conversionConfig has required structure for profiles with rules
|
||||||
return;
|
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', () => {
|
it('should have valid fileMap with required files for each profile', () => {
|
||||||
const expectedFiles = [
|
const expectedRuleFiles = [
|
||||||
'cursor_rules.mdc',
|
'cursor_rules.mdc',
|
||||||
'dev_workflow.mdc',
|
'dev_workflow.mdc',
|
||||||
'self_improve.mdc',
|
'self_improve.mdc',
|
||||||
'taskmaster.mdc'
|
'taskmaster.mdc'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Simple profiles that only copy files (no rule transformation)
|
|
||||||
const simpleProfiles = ['claude', 'codex'];
|
|
||||||
|
|
||||||
RULE_PROFILES.forEach((profile) => {
|
RULE_PROFILES.forEach((profile) => {
|
||||||
const profileConfig = getRulesProfile(profile);
|
const profileConfig = getRulesProfile(profile);
|
||||||
|
|
||||||
@@ -120,33 +118,43 @@ describe('Rule Transformer - General', () => {
|
|||||||
expect(typeof profileConfig.fileMap).toBe('object');
|
expect(typeof profileConfig.fileMap).toBe('object');
|
||||||
expect(profileConfig.fileMap).not.toBeNull();
|
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);
|
const fileMapKeys = Object.keys(profileConfig.fileMap);
|
||||||
|
|
||||||
|
// All profiles should have some fileMap entries now
|
||||||
expect(fileMapKeys.length).toBeGreaterThan(0);
|
expect(fileMapKeys.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
// Check that all expected source files are defined in fileMap
|
// Check if this profile has rule files or asset files
|
||||||
expectedFiles.forEach((expectedFile) => {
|
const hasRuleFiles = expectedRuleFiles.some((file) =>
|
||||||
expect(fileMapKeys).toContain(expectedFile);
|
fileMapKeys.includes(file)
|
||||||
expect(typeof profileConfig.fileMap[expectedFile]).toBe('string');
|
);
|
||||||
expect(profileConfig.fileMap[expectedFile].length).toBeGreaterThan(0);
|
const hasAssetFiles = fileMapKeys.some(
|
||||||
});
|
(file) => !expectedRuleFiles.includes(file)
|
||||||
|
);
|
||||||
|
|
||||||
// Verify fileMap has exactly the expected files
|
if (hasRuleFiles) {
|
||||||
expect(fileMapKeys.sort()).toEqual(expectedFiles.sort());
|
// 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', () => {
|
describe('MCP Configuration Properties', () => {
|
||||||
it('should have all required MCP properties for each profile', () => {
|
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) => {
|
RULE_PROFILES.forEach((profile) => {
|
||||||
const profileConfig = getRulesProfile(profile);
|
const profileConfig = getRulesProfile(profile);
|
||||||
|
|
||||||
@@ -155,23 +163,23 @@ describe('Rule Transformer - General', () => {
|
|||||||
expect(profileConfig).toHaveProperty('mcpConfigName');
|
expect(profileConfig).toHaveProperty('mcpConfigName');
|
||||||
expect(profileConfig).toHaveProperty('mcpConfigPath');
|
expect(profileConfig).toHaveProperty('mcpConfigPath');
|
||||||
|
|
||||||
// Simple profiles have no MCP configuration
|
// Check types based on MCP configuration
|
||||||
if (simpleProfiles.includes(profile)) {
|
expect(typeof profileConfig.mcpConfig).toBe('boolean');
|
||||||
expect(profileConfig.mcpConfig).toBe(false);
|
|
||||||
|
if (profileConfig.mcpConfig === false) {
|
||||||
|
// Profiles without MCP configuration
|
||||||
expect(profileConfig.mcpConfigName).toBe(null);
|
expect(profileConfig.mcpConfigName).toBe(null);
|
||||||
expect(profileConfig.mcpConfigPath).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: {
|
cline: {
|
||||||
mcpConfig: false,
|
mcpConfig: false,
|
||||||
mcpConfigName: 'cline_mcp_settings.json',
|
mcpConfigName: null,
|
||||||
expectedPath: '.clinerules/cline_mcp_settings.json'
|
expectedPath: null
|
||||||
},
|
},
|
||||||
codex: {
|
codex: {
|
||||||
mcpConfig: false,
|
mcpConfig: false,
|
||||||
@@ -197,6 +205,11 @@ describe('Rule Transformer - General', () => {
|
|||||||
mcpConfigName: 'mcp.json',
|
mcpConfigName: 'mcp.json',
|
||||||
expectedPath: '.cursor/mcp.json'
|
expectedPath: '.cursor/mcp.json'
|
||||||
},
|
},
|
||||||
|
gemini: {
|
||||||
|
mcpConfig: true,
|
||||||
|
mcpConfigName: 'settings.json',
|
||||||
|
expectedPath: '.gemini/settings.json'
|
||||||
|
},
|
||||||
roo: {
|
roo: {
|
||||||
mcpConfig: true,
|
mcpConfig: true,
|
||||||
mcpConfigName: 'mcp.json',
|
mcpConfigName: 'mcp.json',
|
||||||
@@ -204,8 +217,8 @@ describe('Rule Transformer - General', () => {
|
|||||||
},
|
},
|
||||||
trae: {
|
trae: {
|
||||||
mcpConfig: false,
|
mcpConfig: false,
|
||||||
mcpConfigName: 'trae_mcp_settings.json',
|
mcpConfigName: null,
|
||||||
expectedPath: '.trae/trae_mcp_settings.json'
|
expectedPath: null
|
||||||
},
|
},
|
||||||
vscode: {
|
vscode: {
|
||||||
mcpConfig: true,
|
mcpConfig: true,
|
||||||
@@ -230,31 +243,28 @@ describe('Rule Transformer - General', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should have consistent profileDir and mcpConfigPath relationship', () => {
|
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) => {
|
RULE_PROFILES.forEach((profile) => {
|
||||||
const profileConfig = getRulesProfile(profile);
|
const profileConfig = getRulesProfile(profile);
|
||||||
|
|
||||||
// Simple profiles have null mcpConfigPath
|
if (profileConfig.mcpConfig === false) {
|
||||||
if (simpleProfiles.includes(profile)) {
|
// Profiles without MCP configuration have null mcpConfigPath
|
||||||
expect(profileConfig.mcpConfigPath).toBe(null);
|
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, '\\$&')}$`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -136,8 +136,8 @@ describe('Selective Rules Removal', () => {
|
|||||||
expect(result.filesRemoved).toEqual([
|
expect(result.filesRemoved).toEqual([
|
||||||
'cursor_rules.mdc',
|
'cursor_rules.mdc',
|
||||||
'taskmaster/dev_workflow.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');
|
expect(result.notice).toContain('Preserved 2 existing rule files');
|
||||||
|
|
||||||
@@ -226,8 +226,8 @@ describe('Selective Rules Removal', () => {
|
|||||||
expect(result.filesRemoved).toEqual([
|
expect(result.filesRemoved).toEqual([
|
||||||
'cursor_rules.mdc',
|
'cursor_rules.mdc',
|
||||||
'taskmaster/dev_workflow.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,
|
// 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
|
// Mock sequence: only Task Master rules, rules dir removed, but profile dir not empty due to MCP
|
||||||
mockReaddirSync
|
mockReaddirSync
|
||||||
.mockReturnValueOnce(['cursor_rules.mdc']) // Only Task Master files
|
.mockReturnValueOnce(['cursor_rules.mdc']) // Only Task Master files
|
||||||
.mockReturnValueOnce([]) // rules dir empty after removal
|
.mockReturnValueOnce(['my_custom_rule.mdc']) // rules dir has other files remaining
|
||||||
.mockReturnValueOnce(['mcp.json']); // Profile dir has MCP config 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)
|
// Mock MCP config with multiple servers (Task Master will be removed, others preserved)
|
||||||
const mockMcpConfig = {
|
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
|
// Mock sequence: only Task Master rules, rules dir removed, but profile dir has other files/folders
|
||||||
mockReaddirSync
|
mockReaddirSync
|
||||||
.mockReturnValueOnce(['cursor_rules.mdc']) // Only Task Master files
|
.mockReturnValueOnce(['cursor_rules.mdc']) // Only Task Master files (initial check)
|
||||||
.mockReturnValueOnce([]) // rules dir empty after removal
|
.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
|
.mockReturnValueOnce(['workflows', 'custom-config.json']); // Profile dir has other files/folders
|
||||||
|
|
||||||
// Mock MCP config with only Task Master (will be completely deleted)
|
// 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.success).toBe(true);
|
||||||
expect(result.profileDirRemoved).toBe(false);
|
expect(result.profileDirRemoved).toBe(false);
|
||||||
expect(result.mcpResult.deleted).toBe(true);
|
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)
|
// Verify profile directory was NOT removed (other files/folders exist)
|
||||||
expect(mockRmSync).not.toHaveBeenCalledWith(
|
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
|
// Mock mixed scenario: some Task Master files, some existing files, other MCP servers
|
||||||
mockExistsSync.mockImplementation((filePath) => {
|
mockExistsSync.mockImplementation((filePath) => {
|
||||||
if (filePath.includes('.cursor')) return true;
|
// Only .cursor directories exist
|
||||||
if (filePath.includes('mcp.json')) return true;
|
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;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ describe('Rules Subdirectory Support Feature', () => {
|
|||||||
expect(cursorProfile.supportsRulesSubdirectories).toBe(true);
|
expect(cursorProfile.supportsRulesSubdirectories).toBe(true);
|
||||||
|
|
||||||
// Verify that Cursor uses taskmaster subdirectories in its file mapping
|
// 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'
|
'taskmaster/dev_workflow.mdc'
|
||||||
);
|
);
|
||||||
expect(cursorProfile.fileMap['taskmaster.mdc']).toBe(
|
expect(cursorProfile.fileMap['rules/taskmaster.mdc']).toBe(
|
||||||
'taskmaster/taskmaster.mdc'
|
'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
|
// Verify that these profiles do NOT use taskmaster subdirectories in their file mapping
|
||||||
const expectedExt = profile.targetExtension || '.md';
|
const expectedExt = profile.targetExtension || '.md';
|
||||||
expect(profile.fileMap['dev_workflow.mdc']).toBe(
|
expect(profile.fileMap['rules/dev_workflow.mdc']).toBe(
|
||||||
`dev_workflow${expectedExt}`
|
`dev_workflow${expectedExt}`
|
||||||
);
|
);
|
||||||
expect(profile.fileMap['taskmaster.mdc']).toBe(
|
expect(profile.fileMap['rules/taskmaster.mdc']).toBe(
|
||||||
`taskmaster${expectedExt}`
|
`taskmaster${expectedExt}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user