Compare commits
16 Commits
task-maste
...
task-maste
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e81040def5 | ||
|
|
597f6b03b4 | ||
|
|
a7ad4c8e92 | ||
|
|
0d54747894 | ||
|
|
df26c65632 | ||
|
|
e80e5bb7cd | ||
|
|
c4f92f6a0a | ||
|
|
be0c0f267c | ||
|
|
a983f75d4f | ||
|
|
e743aaa8c2 | ||
|
|
16ffffaf68 | ||
|
|
f254aed4a6 | ||
|
|
dd3b47bb2b | ||
|
|
37af0f1912 | ||
|
|
8783708e5e | ||
|
|
4dad2fd613 |
93
.claude/commands/tm/remove-subtasks/remove-all-subtasks.md
Normal file
93
.claude/commands/tm/remove-subtasks/remove-all-subtasks.md
Normal file
@@ -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
.claude/commands/tm/remove-subtasks/remove-subtasks.md
Normal file
86
.claude/commands/tm/remove-subtasks/remove-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
|
||||||
|
```
|
||||||
57
.github/workflows/claude-docs-trigger.yml
vendored
Normal file
57
.github/workflows/claude-docs-trigger.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
name: Trigger Claude Documentation Update
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- next
|
||||||
|
paths-ignore:
|
||||||
|
- "apps/docs/**"
|
||||||
|
- "*.md"
|
||||||
|
- ".github/workflows/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
trigger-docs-update:
|
||||||
|
# Only run if changes were merged (not direct pushes from bots)
|
||||||
|
if: github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2 # Need previous commit for comparison
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
run: |
|
||||||
|
echo "Changed files in this push:"
|
||||||
|
git diff --name-only HEAD^ HEAD | tee changed_files.txt
|
||||||
|
|
||||||
|
# Store changed files for Claude to analyze (escaped for JSON)
|
||||||
|
CHANGED_FILES=$(git diff --name-only HEAD^ HEAD | jq -Rs .)
|
||||||
|
echo "changed_files=$CHANGED_FILES" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Get the commit message (escaped for JSON)
|
||||||
|
COMMIT_MSG=$(git log -1 --pretty=%B | jq -Rs .)
|
||||||
|
echo "commit_message=$COMMIT_MSG" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Get diff for documentation context (escaped for JSON)
|
||||||
|
COMMIT_DIFF=$(git diff HEAD^ HEAD --stat | jq -Rs .)
|
||||||
|
echo "commit_diff=$COMMIT_DIFF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Get commit SHA
|
||||||
|
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Trigger Claude workflow
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# Trigger the Claude docs updater workflow with the change information
|
||||||
|
gh workflow run claude-docs-updater.yml \
|
||||||
|
--ref next \
|
||||||
|
-f commit_sha="${{ steps.changed-files.outputs.commit_sha }}" \
|
||||||
|
-f commit_message=${{ steps.changed-files.outputs.commit_message }} \
|
||||||
|
-f changed_files=${{ steps.changed-files.outputs.changed_files }} \
|
||||||
|
-f commit_diff=${{ steps.changed-files.outputs.commit_diff }}
|
||||||
65
.github/workflows/claude-docs-updater.yml
vendored
65
.github/workflows/claude-docs-updater.yml
vendored
@@ -1,18 +1,27 @@
|
|||||||
name: Claude Documentation Updater
|
name: Claude Documentation Updater
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
workflow_dispatch:
|
||||||
branches:
|
inputs:
|
||||||
- next
|
commit_sha:
|
||||||
paths-ignore:
|
description: 'The commit SHA that triggered this update'
|
||||||
- "apps/docs/**"
|
required: true
|
||||||
- "*.md"
|
type: string
|
||||||
- ".github/workflows/**"
|
commit_message:
|
||||||
|
description: 'The commit message'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
changed_files:
|
||||||
|
description: 'List of changed files'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
commit_diff:
|
||||||
|
description: 'Diff summary of changes'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-docs:
|
update-docs:
|
||||||
# Only run if changes were merged (not direct pushes from bots)
|
|
||||||
if: github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -22,28 +31,8 @@ jobs:
|
|||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2 # Need previous commit for comparison
|
ref: next
|
||||||
|
fetch-depth: 0 # Need full history to checkout specific commit
|
||||||
- name: Get changed files
|
|
||||||
id: changed-files
|
|
||||||
run: |
|
|
||||||
echo "Changed files in this push:"
|
|
||||||
git diff --name-only HEAD^ HEAD | tee changed_files.txt
|
|
||||||
|
|
||||||
# Store changed files for Claude to analyze
|
|
||||||
echo "changed_files<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
git diff --name-only HEAD^ HEAD >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Get the commit message and changes summary
|
|
||||||
echo "commit_message<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
git log -1 --pretty=%B >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Get diff for documentation context
|
|
||||||
echo "commit_diff<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
git diff HEAD^ HEAD --stat >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Create docs update branch
|
- name: Create docs update branch
|
||||||
id: create-branch
|
id: create-branch
|
||||||
@@ -71,12 +60,12 @@ jobs:
|
|||||||
You are a documentation specialist. Analyze the recent changes pushed to the 'next' branch and update the documentation accordingly.
|
You are a documentation specialist. Analyze the recent changes pushed to the 'next' branch and update the documentation accordingly.
|
||||||
|
|
||||||
Recent changes:
|
Recent changes:
|
||||||
- Commit: ${{ steps.changed-files.outputs.commit_message }}
|
- Commit: ${{ inputs.commit_message }}
|
||||||
- Changed files:
|
- Changed files:
|
||||||
${{ steps.changed-files.outputs.changed_files }}
|
${{ inputs.changed_files }}
|
||||||
|
|
||||||
- Changes summary:
|
- Changes summary:
|
||||||
${{ steps.changed-files.outputs.commit_diff }}
|
${{ inputs.commit_diff }}
|
||||||
|
|
||||||
Your task:
|
Your task:
|
||||||
1. Analyze the changes to understand what functionality was added, modified, or removed
|
1. Analyze the changes to understand what functionality was added, modified, or removed
|
||||||
@@ -113,7 +102,7 @@ jobs:
|
|||||||
|
|
||||||
This PR was automatically generated to update documentation based on recent changes.
|
This PR was automatically generated to update documentation based on recent changes.
|
||||||
|
|
||||||
Original commit: ${{ steps.changed-files.outputs.commit_message }}
|
Original commit: ${{ inputs.commit_message }}
|
||||||
|
|
||||||
Co-authored-by: Claude <claude-assistant@anthropic.com>"
|
Co-authored-by: Claude <claude-assistant@anthropic.com>"
|
||||||
fi
|
fi
|
||||||
@@ -133,12 +122,12 @@ jobs:
|
|||||||
This PR automatically updates documentation based on recent changes merged to the \`next\` branch.
|
This PR automatically updates documentation based on recent changes merged to the \`next\` branch.
|
||||||
|
|
||||||
### Original Changes
|
### Original Changes
|
||||||
**Commit:** ${{ github.sha }}
|
**Commit:** ${{ inputs.commit_sha }}
|
||||||
**Message:** ${{ steps.changed-files.outputs.commit_message }}
|
**Message:** ${{ inputs.commit_message }}
|
||||||
|
|
||||||
### Changed Files in Original Commit
|
### Changed Files in Original Commit
|
||||||
\`\`\`
|
\`\`\`
|
||||||
${{ steps.changed-files.outputs.changed_files }}
|
${{ inputs.changed_files }}
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
### Documentation Updates
|
### Documentation Updates
|
||||||
|
|||||||
88
CHANGELOG.md
88
CHANGELOG.md
@@ -1,5 +1,93 @@
|
|||||||
# task-master-ai
|
# task-master-ai
|
||||||
|
|
||||||
|
## 0.26.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- [#1133](https://github.com/eyaltoledano/claude-task-master/pull/1133) [`df26c65`](https://github.com/eyaltoledano/claude-task-master/commit/df26c65632000874a73504963b08f18c46283144) Thanks [@neonwatty](https://github.com/neonwatty)! - Restore Taskmaster claude-code commands and move clear commands under /remove to avoid collision with the claude-code /clear command.
|
||||||
|
|
||||||
|
- [#1163](https://github.com/eyaltoledano/claude-task-master/pull/1163) [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Gemini CLI provider with codebase-aware task generation
|
||||||
|
|
||||||
|
Added automatic codebase analysis for Gemini CLI provider in parse-prd, and analyze-complexity, add-task, udpate-task, update, update-subtask commands
|
||||||
|
When using Gemini CLI as the AI provider, Task Master now instructs the AI to analyze the project structure, existing implementations, and patterns before generating tasks or subtasks
|
||||||
|
Tasks and subtasks generated by Claude Code are now informed by actual codebase analysis, resulting in more accurate and contextual outputs
|
||||||
|
|
||||||
|
- [#1165](https://github.com/eyaltoledano/claude-task-master/pull/1165) [`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add configurable codebase analysis feature flag with multiple configuration sources
|
||||||
|
|
||||||
|
Users can now control whether codebase analysis features (Claude Code and Gemini CLI integration) are enabled through environment variables, MCP configuration, or project config files.
|
||||||
|
|
||||||
|
Priority order: .env > MCP session env > .taskmaster/config.json.
|
||||||
|
|
||||||
|
Set `TASKMASTER_ENABLE_CODEBASE_ANALYSIS=false` in `.env` to disable codebase analysis prompts and tool integration.
|
||||||
|
|
||||||
|
- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - feat(move): improve cross-tag move UX and safety
|
||||||
|
- CLI: print "Next Steps" tips after cross-tag moves that used --ignore-dependencies (validate/fix guidance)
|
||||||
|
- CLI: show dedicated help block on ID collisions (destination tag already has the ID)
|
||||||
|
- Core: add structured suggestions to TASK_ALREADY_EXISTS errors
|
||||||
|
- MCP: map ID collision errors to TASK_ALREADY_EXISTS and include suggestions
|
||||||
|
- Tests: cover MCP options, error suggestions, CLI tips printing, and integration error payload suggestions
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
- [#1162](https://github.com/eyaltoledano/claude-task-master/pull/1162) [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Claude Code and Google CLI integration with automatic codebase analysis for task operations
|
||||||
|
|
||||||
|
When using Claude Code as the AI provider, task management commands now automatically analyze your codebase before generating or updating tasks. This provides more accurate, context-aware implementation details that align with your project's existing architecture and patterns.
|
||||||
|
|
||||||
|
Commands contextualised:
|
||||||
|
- add-task
|
||||||
|
- update-subtask
|
||||||
|
- update-task
|
||||||
|
- update
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - docs(move): clarify cross-tag move docs; deprecate "force"; add explicit --with-dependencies/--ignore-dependencies examples
|
||||||
|
|
||||||
|
## 0.26.0-rc.1
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- [#1165](https://github.com/eyaltoledano/claude-task-master/pull/1165) [`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add configurable codebase analysis feature flag with multiple configuration sources
|
||||||
|
|
||||||
|
Users can now control whether codebase analysis features (Claude Code and Gemini CLI integration) are enabled through environment variables, MCP configuration, or project config files.
|
||||||
|
|
||||||
|
Priority order: .env > MCP session env > .taskmaster/config.json.
|
||||||
|
|
||||||
|
Set `TASKMASTER_ENABLE_CODEBASE_ANALYSIS=false` in `.env` to disable codebase analysis prompts and tool integration.
|
||||||
|
|
||||||
|
## 0.26.0-rc.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- [#1163](https://github.com/eyaltoledano/claude-task-master/pull/1163) [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Gemini CLI provider with codebase-aware task generation
|
||||||
|
|
||||||
|
Added automatic codebase analysis for Gemini CLI provider in parse-prd, and analyze-complexity, add-task, udpate-task, update, update-subtask commands
|
||||||
|
When using Gemini CLI as the AI provider, Task Master now instructs the AI to analyze the project structure, existing implementations, and patterns before generating tasks or subtasks
|
||||||
|
Tasks and subtasks generated by Claude Code are now informed by actual codebase analysis, resulting in more accurate and contextual outputs
|
||||||
|
|
||||||
|
- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - feat(move): improve cross-tag move UX and safety
|
||||||
|
- CLI: print "Next Steps" tips after cross-tag moves that used --ignore-dependencies (validate/fix guidance)
|
||||||
|
- CLI: show dedicated help block on ID collisions (destination tag already has the ID)
|
||||||
|
- Core: add structured suggestions to TASK_ALREADY_EXISTS errors
|
||||||
|
- MCP: map ID collision errors to TASK_ALREADY_EXISTS and include suggestions
|
||||||
|
- Tests: cover MCP options, error suggestions, CLI tips printing, and integration error payload suggestions
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
- [#1162](https://github.com/eyaltoledano/claude-task-master/pull/1162) [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Claude Code and Google CLI integration with automatic codebase analysis for task operations
|
||||||
|
|
||||||
|
When using Claude Code as the AI provider, task management commands now automatically analyze your codebase before generating or updating tasks. This provides more accurate, context-aware implementation details that align with your project's existing architecture and patterns.
|
||||||
|
|
||||||
|
Commands contextualised:
|
||||||
|
- add-task
|
||||||
|
- update-subtask
|
||||||
|
- update-task
|
||||||
|
- update
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - docs(move): clarify cross-tag move docs; deprecate "force"; add explicit --with-dependencies/--ignore-dependencies examples
|
||||||
|
|
||||||
## 0.25.1
|
## 0.25.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
# docs
|
# docs
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
## 0.0.1
|
## 0.0.1
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docs",
|
"name": "docs",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Task Master documentation powered by Mintlify",
|
"description": "Task Master documentation powered by Mintlify",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,5 +1,26 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 0.24.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`df26c65`](https://github.com/eyaltoledano/claude-task-master/commit/df26c65632000874a73504963b08f18c46283144), [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66), [`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e), [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9)]:
|
||||||
|
- task-master-ai@0.26.0
|
||||||
|
|
||||||
|
## 0.24.2-rc.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e)]:
|
||||||
|
- task-master-ai@0.26.0-rc.1
|
||||||
|
|
||||||
|
## 0.24.2-rc.0
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66), [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9)]:
|
||||||
|
- task-master-ai@0.26.0-rc.0
|
||||||
|
|
||||||
## 0.24.1
|
## 0.24.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -3,23 +3,15 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"displayName": "TaskMaster",
|
"displayName": "TaskMaster",
|
||||||
"description": "A visual Kanban board interface for TaskMaster projects in VS Code",
|
"description": "A visual Kanban board interface for TaskMaster projects in VS Code",
|
||||||
"version": "0.24.1",
|
"version": "0.24.2",
|
||||||
"publisher": "Hamster",
|
"publisher": "Hamster",
|
||||||
"icon": "assets/icon.png",
|
"icon": "assets/icon.png",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.93.0"
|
"vscode": "^1.93.0"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": ["AI", "Visualization", "Education", "Other"],
|
||||||
"AI",
|
|
||||||
"Visualization",
|
|
||||||
"Education",
|
|
||||||
"Other"
|
|
||||||
],
|
|
||||||
"main": "./dist/extension.js",
|
"main": "./dist/extension.js",
|
||||||
"activationEvents": [
|
"activationEvents": ["onStartupFinished", "workspaceContains:.taskmaster/**"],
|
||||||
"onStartupFinished",
|
|
||||||
"workspaceContains:.taskmaster/**"
|
|
||||||
],
|
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"viewsContainers": {
|
"viewsContainers": {
|
||||||
"activitybar": [
|
"activitybar": [
|
||||||
@@ -147,11 +139,7 @@
|
|||||||
},
|
},
|
||||||
"taskmaster.ui.theme": {
|
"taskmaster.ui.theme": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["auto", "light", "dark"],
|
||||||
"auto",
|
|
||||||
"light",
|
|
||||||
"dark"
|
|
||||||
],
|
|
||||||
"default": "auto",
|
"default": "auto",
|
||||||
"description": "UI theme preference"
|
"description": "UI theme preference"
|
||||||
},
|
},
|
||||||
@@ -212,12 +200,7 @@
|
|||||||
},
|
},
|
||||||
"taskmaster.debug.logLevel": {
|
"taskmaster.debug.logLevel": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["error", "warn", "info", "debug"],
|
||||||
"error",
|
|
||||||
"warn",
|
|
||||||
"info",
|
|
||||||
"debug"
|
|
||||||
],
|
|
||||||
"default": "info",
|
"default": "info",
|
||||||
"description": "Logging level"
|
"description": "Logging level"
|
||||||
},
|
},
|
||||||
@@ -256,7 +239,7 @@
|
|||||||
"check-types": "tsc --noEmit"
|
"check-types": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"task-master-ai": "0.25.1"
|
"task-master-ai": "0.26.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
|||||||
@@ -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/remove-subtasks/remove-subtasks.md
Normal file
86
assets/claude/commands/tm/remove-subtasks/remove-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
|
||||||
|
```
|
||||||
@@ -65,11 +65,10 @@ This removes the dependency relationships and moves only the specified task.
|
|||||||
|
|
||||||
### Force Move
|
### Force Move
|
||||||
|
|
||||||
Force the move even with dependency conflicts:
|
Note: Force moves are no longer supported. Instead, use one of these options:
|
||||||
|
|
||||||
```bash
|
- `--with-dependencies` — move dependents together
|
||||||
task-master move --from=5 --from-tag=backlog --to-tag=in-progress --force
|
- `--ignore-dependencies` — break cross-tag dependencies
|
||||||
```
|
|
||||||
|
|
||||||
⚠️ **Warning**: This may break dependency relationships and should be used with caution.
|
⚠️ **Warning**: This may break dependency relationships and should be used with caution.
|
||||||
|
|
||||||
@@ -93,7 +92,7 @@ Resolution options:
|
|||||||
2. Break dependencies: task-master move --from=5,6 --from-tag=backlog --to-tag=in-progress --ignore-dependencies
|
2. Break dependencies: task-master move --from=5,6 --from-tag=backlog --to-tag=in-progress --ignore-dependencies
|
||||||
3. Validate and fix dependencies: task-master validate-dependencies && task-master fix-dependencies
|
3. Validate and fix dependencies: task-master validate-dependencies && task-master fix-dependencies
|
||||||
4. Move dependencies first: task-master move --from=2,3 --from-tag=backlog --to-tag=in-progress
|
4. Move dependencies first: task-master move --from=2,3 --from-tag=backlog --to-tag=in-progress
|
||||||
5. Force move (may break dependencies): task-master move --from=5,6 --from-tag=backlog --to-tag=in-progress --force
|
5. After deciding, re-run the move with either --with-dependencies or --ignore-dependencies
|
||||||
```
|
```
|
||||||
|
|
||||||
### Subtask Movement Restrictions
|
### Subtask Movement Restrictions
|
||||||
@@ -149,7 +148,6 @@ task-master fix-dependencies
|
|||||||
|
|
||||||
- **`--with-dependencies`**: When you want to maintain task relationships
|
- **`--with-dependencies`**: When you want to maintain task relationships
|
||||||
- **`--ignore-dependencies`**: When you want to break cross-tag dependencies
|
- **`--ignore-dependencies`**: When you want to break cross-tag dependencies
|
||||||
- **`--force`**: Only when you understand the consequences
|
|
||||||
|
|
||||||
### 3. Organize by Context
|
### 3. Organize by Context
|
||||||
|
|
||||||
@@ -265,9 +263,14 @@ task-master move --from=5 --from-tag=backlog --to-tag=done --ignore-dependencies
|
|||||||
|
|
||||||
### Scenario 3: Force Move
|
### Scenario 3: Force Move
|
||||||
|
|
||||||
|
Choose one of these options explicitly:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Force move despite conflicts
|
# Move together with dependencies
|
||||||
task-master move --from=5 --from-tag=backlog --to-tag=in-progress --force
|
task-master move --from=5 --from-tag=backlog --to-tag=in-progress --with-dependencies
|
||||||
|
|
||||||
|
# Or break dependencies
|
||||||
|
task-master move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies
|
||||||
```
|
```
|
||||||
|
|
||||||
### Scenario 4: Moving Subtasks
|
### Scenario 4: Moving Subtasks
|
||||||
|
|||||||
@@ -189,6 +189,17 @@ export async function moveTaskCrossTagDirect(args, log, context = {}) {
|
|||||||
'Verify task IDs exist: task-master list',
|
'Verify task IDs exist: task-master list',
|
||||||
'Check task details: task-master show <id>'
|
'Check task details: task-master show <id>'
|
||||||
];
|
];
|
||||||
|
} else if (
|
||||||
|
error.code === 'TASK_ALREADY_EXISTS' ||
|
||||||
|
error.message?.includes('already exists in target tag')
|
||||||
|
) {
|
||||||
|
// Target tag has an ID collision
|
||||||
|
errorCode = 'TASK_ALREADY_EXISTS';
|
||||||
|
suggestions = [
|
||||||
|
'Choose a different target tag without conflicting IDs',
|
||||||
|
'Move a different set of IDs (avoid existing ones)',
|
||||||
|
'If needed, move within-tag to a new ID first, then cross-tag move'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
4586
package-lock.json
generated
4586
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "0.25.1",
|
"version": "0.26.0",
|
||||||
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -9,10 +9,7 @@
|
|||||||
"task-master-mcp": "mcp-server/server.js",
|
"task-master-mcp": "mcp-server/server.js",
|
||||||
"task-master-ai": "mcp-server/server.js"
|
"task-master-ai": "mcp-server/server.js"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": ["apps/*", "."],
|
||||||
"apps/*",
|
|
||||||
"."
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
||||||
"test:fails": "node --experimental-vm-modules node_modules/.bin/jest --onlyFailures",
|
"test:fails": "node --experimental-vm-modules node_modules/.bin/jest --onlyFailures",
|
||||||
@@ -91,7 +88,7 @@
|
|||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@anthropic-ai/claude-code": "^1.0.88",
|
"@anthropic-ai/claude-code": "^1.0.88",
|
||||||
"@biomejs/cli-linux-x64": "^1.9.4",
|
"@biomejs/cli-linux-x64": "^1.9.4",
|
||||||
"ai-sdk-provider-gemini-cli": "^0.1.1"
|
"ai-sdk-provider-gemini-cli": "^0.1.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
|
|||||||
@@ -4103,12 +4103,7 @@ Examples:
|
|||||||
' task-master move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies'
|
' task-master move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies'
|
||||||
) +
|
) +
|
||||||
'\n\n' +
|
'\n\n' +
|
||||||
chalk.white(' # Force move (may break dependencies)') +
|
|
||||||
'\n' +
|
'\n' +
|
||||||
chalk.white(
|
|
||||||
' task-master move --from=5 --from-tag=backlog --to-tag=in-progress --force'
|
|
||||||
) +
|
|
||||||
'\n\n' +
|
|
||||||
chalk.yellow.bold('Best Practices:') +
|
chalk.yellow.bold('Best Practices:') +
|
||||||
'\n' +
|
'\n' +
|
||||||
chalk.white(
|
chalk.white(
|
||||||
@@ -4119,10 +4114,6 @@ Examples:
|
|||||||
' • Use --ignore-dependencies to break cross-tag dependencies'
|
' • Use --ignore-dependencies to break cross-tag dependencies'
|
||||||
) +
|
) +
|
||||||
'\n' +
|
'\n' +
|
||||||
chalk.white(
|
|
||||||
' • Use --force only when you understand the consequences'
|
|
||||||
) +
|
|
||||||
'\n' +
|
|
||||||
chalk.white(
|
chalk.white(
|
||||||
' • Check dependencies first: task-master validate-dependencies'
|
' • Check dependencies first: task-master validate-dependencies'
|
||||||
) +
|
) +
|
||||||
@@ -4184,6 +4175,12 @@ Examples:
|
|||||||
|
|
||||||
console.log(chalk.green(`✓ ${result.message}`));
|
console.log(chalk.green(`✓ ${result.message}`));
|
||||||
|
|
||||||
|
// Print any tips returned from the move operation (e.g., after ignoring dependencies)
|
||||||
|
if (Array.isArray(result.tips) && result.tips.length > 0) {
|
||||||
|
console.log('\n' + chalk.yellow.bold('Next Steps:'));
|
||||||
|
result.tips.forEach((t) => console.log(chalk.white(` • ${t}`)));
|
||||||
|
}
|
||||||
|
|
||||||
// Check if source tag still contains tasks before regenerating files
|
// Check if source tag still contains tasks before regenerating files
|
||||||
const tasksData = readJSON(
|
const tasksData = readJSON(
|
||||||
taskMaster.getTasksPath(),
|
taskMaster.getTasksPath(),
|
||||||
@@ -4450,6 +4447,27 @@ Examples:
|
|||||||
await handleWithinTagMove(moveContext);
|
await handleWithinTagMove(moveContext);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const errMsg = String(error && (error.message || error));
|
||||||
|
if (errMsg.includes('already exists in target tag')) {
|
||||||
|
console.error(chalk.red(`Error: ${errMsg}`));
|
||||||
|
console.log(
|
||||||
|
'\n' +
|
||||||
|
chalk.yellow.bold('Conflict: ID already exists in target tag') +
|
||||||
|
'\n' +
|
||||||
|
chalk.white(
|
||||||
|
' • Choose a different target tag without conflicting IDs'
|
||||||
|
) +
|
||||||
|
'\n' +
|
||||||
|
chalk.white(
|
||||||
|
' • Move a different set of IDs (avoid existing ones)'
|
||||||
|
) +
|
||||||
|
'\n' +
|
||||||
|
chalk.white(
|
||||||
|
' • If needed, move within-tag to a new ID first, then cross-tag move'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
handleMoveError(error, moveContext);
|
handleMoveError(error, moveContext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ const DEFAULTS = {
|
|||||||
projectName: 'Task Master',
|
projectName: 'Task Master',
|
||||||
ollamaBaseURL: 'http://localhost:11434/api',
|
ollamaBaseURL: 'http://localhost:11434/api',
|
||||||
bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com',
|
bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com',
|
||||||
responseLanguage: 'English'
|
responseLanguage: 'English',
|
||||||
|
enableCodebaseAnalysis: true
|
||||||
},
|
},
|
||||||
claudeCode: {}
|
claudeCode: {}
|
||||||
};
|
};
|
||||||
@@ -427,6 +428,63 @@ function getResearchProvider(explicitRoot = null) {
|
|||||||
return getModelConfigForRole('research', explicitRoot).provider;
|
return getModelConfigForRole('research', explicitRoot).provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if codebase analysis feature flag is enabled across all sources
|
||||||
|
* Priority: .env > MCP env > config.json
|
||||||
|
* @param {object|null} session - MCP session object (optional)
|
||||||
|
* @param {string|null} projectRoot - Project root path (optional)
|
||||||
|
* @returns {boolean} True if codebase analysis is enabled
|
||||||
|
*/
|
||||||
|
function isCodebaseAnalysisEnabled(session = null, projectRoot = null) {
|
||||||
|
// Priority 1: Environment variable
|
||||||
|
const envFlag = resolveEnvVariable(
|
||||||
|
'TASKMASTER_ENABLE_CODEBASE_ANALYSIS',
|
||||||
|
session,
|
||||||
|
projectRoot
|
||||||
|
);
|
||||||
|
if (envFlag !== null && envFlag !== undefined && envFlag !== '') {
|
||||||
|
return envFlag.toLowerCase() === 'true' || envFlag === '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority 2: MCP session environment
|
||||||
|
if (session?.env?.TASKMASTER_ENABLE_CODEBASE_ANALYSIS) {
|
||||||
|
const mcpFlag = session.env.TASKMASTER_ENABLE_CODEBASE_ANALYSIS;
|
||||||
|
return mcpFlag.toLowerCase() === 'true' || mcpFlag === '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority 3: Configuration file
|
||||||
|
const globalConfig = getGlobalConfig(projectRoot);
|
||||||
|
return globalConfig.enableCodebaseAnalysis !== false; // Default to true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if codebase analysis is available and enabled
|
||||||
|
* @param {boolean} useResearch - Whether to check research provider or main provider
|
||||||
|
* @param {string|null} projectRoot - Project root path (optional)
|
||||||
|
* @param {object|null} session - MCP session object (optional)
|
||||||
|
* @returns {boolean} True if codebase analysis is available and enabled
|
||||||
|
*/
|
||||||
|
function hasCodebaseAnalysis(
|
||||||
|
useResearch = false,
|
||||||
|
projectRoot = null,
|
||||||
|
session = null
|
||||||
|
) {
|
||||||
|
// First check if the feature is enabled
|
||||||
|
if (!isCodebaseAnalysisEnabled(session, projectRoot)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then check if a codebase analysis provider is configured
|
||||||
|
const currentProvider = useResearch
|
||||||
|
? getResearchProvider(projectRoot)
|
||||||
|
: getMainProvider(projectRoot);
|
||||||
|
|
||||||
|
return (
|
||||||
|
currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE ||
|
||||||
|
currentProvider === CUSTOM_PROVIDERS.GEMINI_CLI
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function getResearchModelId(explicitRoot = null) {
|
function getResearchModelId(explicitRoot = null) {
|
||||||
return getModelConfigForRole('research', explicitRoot).modelId;
|
return getModelConfigForRole('research', explicitRoot).modelId;
|
||||||
}
|
}
|
||||||
@@ -542,6 +600,11 @@ function getResponseLanguage(explicitRoot = null) {
|
|||||||
return getGlobalConfig(explicitRoot).responseLanguage;
|
return getGlobalConfig(explicitRoot).responseLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCodebaseAnalysisEnabled(explicitRoot = null) {
|
||||||
|
// Directly return value from config
|
||||||
|
return getGlobalConfig(explicitRoot).enableCodebaseAnalysis;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets model parameters (maxTokens, temperature) for a specific role,
|
* Gets model parameters (maxTokens, temperature) for a specific role,
|
||||||
* considering model-specific overrides from supported-models.json.
|
* considering model-specific overrides from supported-models.json.
|
||||||
@@ -983,6 +1046,7 @@ export {
|
|||||||
getResearchModelId,
|
getResearchModelId,
|
||||||
getResearchMaxTokens,
|
getResearchMaxTokens,
|
||||||
getResearchTemperature,
|
getResearchTemperature,
|
||||||
|
hasCodebaseAnalysis,
|
||||||
getFallbackProvider,
|
getFallbackProvider,
|
||||||
getFallbackModelId,
|
getFallbackModelId,
|
||||||
getFallbackMaxTokens,
|
getFallbackMaxTokens,
|
||||||
@@ -999,6 +1063,8 @@ export {
|
|||||||
getAzureBaseURL,
|
getAzureBaseURL,
|
||||||
getBedrockBaseURL,
|
getBedrockBaseURL,
|
||||||
getResponseLanguage,
|
getResponseLanguage,
|
||||||
|
getCodebaseAnalysisEnabled,
|
||||||
|
isCodebaseAnalysisEnabled,
|
||||||
getParametersForRole,
|
getParametersForRole,
|
||||||
getUserId,
|
getUserId,
|
||||||
// API Key Checkers (still relevant)
|
// API Key Checkers (still relevant)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
markMigrationForNotice
|
markMigrationForNotice
|
||||||
} from '../utils.js';
|
} from '../utils.js';
|
||||||
import { generateObjectService } from '../ai-services-unified.js';
|
import { generateObjectService } from '../ai-services-unified.js';
|
||||||
import { getDefaultPriority } from '../config-manager.js';
|
import { getDefaultPriority, hasCodebaseAnalysis } from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import ContextGatherer from '../utils/contextGatherer.js';
|
import ContextGatherer from '../utils/contextGatherer.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
@@ -425,7 +425,13 @@ async function addTask(
|
|||||||
contextFromArgs,
|
contextFromArgs,
|
||||||
useResearch,
|
useResearch,
|
||||||
priority: effectivePriority,
|
priority: effectivePriority,
|
||||||
dependencies: numericDependencies
|
dependencies: numericDependencies,
|
||||||
|
hasCodebaseAnalysis: hasCodebaseAnalysis(
|
||||||
|
useResearch,
|
||||||
|
projectRoot,
|
||||||
|
session
|
||||||
|
),
|
||||||
|
projectRoot: projectRoot
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import boxen from 'boxen';
|
|||||||
import readline from 'readline';
|
import readline from 'readline';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
import { log, readJSON, writeJSON, isSilentMode } from '../utils.js';
|
import { log, readJSON, isSilentMode } from '../utils.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
startLoadingIndicator,
|
startLoadingIndicator,
|
||||||
@@ -16,8 +16,7 @@ import { generateTextService } from '../ai-services-unified.js';
|
|||||||
import {
|
import {
|
||||||
getDebugFlag,
|
getDebugFlag,
|
||||||
getProjectName,
|
getProjectName,
|
||||||
getMainProvider,
|
hasCodebaseAnalysis
|
||||||
getResearchProvider
|
|
||||||
} from '../config-manager.js';
|
} from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import {
|
import {
|
||||||
@@ -415,16 +414,16 @@ async function analyzeTaskComplexity(options, context = {}) {
|
|||||||
const promptManager = getPromptManager();
|
const promptManager = getPromptManager();
|
||||||
|
|
||||||
// Check if Claude Code is being used as the provider
|
// Check if Claude Code is being used as the provider
|
||||||
const currentProvider = useResearch
|
|
||||||
? getResearchProvider(projectRoot)
|
|
||||||
: getMainProvider(projectRoot);
|
|
||||||
const isClaudeCode = currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE;
|
|
||||||
|
|
||||||
const promptParams = {
|
const promptParams = {
|
||||||
tasks: tasksData.tasks,
|
tasks: tasksData.tasks,
|
||||||
gatheredContext: gatheredContext || '',
|
gatheredContext: gatheredContext || '',
|
||||||
useResearch: useResearch,
|
useResearch: useResearch,
|
||||||
isClaudeCode: isClaudeCode,
|
hasCodebaseAnalysis: hasCodebaseAnalysis(
|
||||||
|
useResearch,
|
||||||
|
projectRoot,
|
||||||
|
session
|
||||||
|
),
|
||||||
projectRoot: projectRoot || ''
|
projectRoot: projectRoot || ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,11 @@ import { generateTextService } from '../ai-services-unified.js';
|
|||||||
import {
|
import {
|
||||||
getDefaultSubtasks,
|
getDefaultSubtasks,
|
||||||
getDebugFlag,
|
getDebugFlag,
|
||||||
getMainProvider,
|
hasCodebaseAnalysis
|
||||||
getResearchProvider
|
|
||||||
} from '../config-manager.js';
|
} from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
import { COMPLEXITY_REPORT_FILE } from '../../../src/constants/paths.js';
|
import { COMPLEXITY_REPORT_FILE } from '../../../src/constants/paths.js';
|
||||||
import { CUSTOM_PROVIDERS } from '../../../src/constants/providers.js';
|
|
||||||
import { ContextGatherer } from '../utils/contextGatherer.js';
|
import { ContextGatherer } from '../utils/contextGatherer.js';
|
||||||
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
|
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
|
||||||
import { flattenTasksWithSubtasks, findProjectRoot } from '../utils.js';
|
import { flattenTasksWithSubtasks, findProjectRoot } from '../utils.js';
|
||||||
@@ -457,11 +455,12 @@ async function expandTask(
|
|||||||
// Load prompts using PromptManager
|
// Load prompts using PromptManager
|
||||||
const promptManager = getPromptManager();
|
const promptManager = getPromptManager();
|
||||||
|
|
||||||
// Check if Claude Code is being used as the provider
|
// Check if a codebase analysis provider is being used
|
||||||
const currentProvider = useResearch
|
const hasCodebaseAnalysisCapability = hasCodebaseAnalysis(
|
||||||
? getResearchProvider(projectRoot)
|
useResearch,
|
||||||
: getMainProvider(projectRoot);
|
projectRoot,
|
||||||
const isClaudeCode = currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE;
|
session
|
||||||
|
);
|
||||||
|
|
||||||
// Combine all context sources into a single additionalContext parameter
|
// Combine all context sources into a single additionalContext parameter
|
||||||
let combinedAdditionalContext = '';
|
let combinedAdditionalContext = '';
|
||||||
@@ -508,7 +507,7 @@ async function expandTask(
|
|||||||
gatheredContext: gatheredContextText || '',
|
gatheredContext: gatheredContextText || '',
|
||||||
useResearch: useResearch,
|
useResearch: useResearch,
|
||||||
expansionPrompt: expansionPromptText || undefined,
|
expansionPrompt: expansionPromptText || undefined,
|
||||||
isClaudeCode: isClaudeCode,
|
hasCodebaseAnalysis: hasCodebaseAnalysisCapability,
|
||||||
projectRoot: projectRoot || ''
|
projectRoot: projectRoot || ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,43 @@ const MOVE_ERROR_CODES = {
|
|||||||
INVALID_TARGET_TAG: 'INVALID_TARGET_TAG'
|
INVALID_TARGET_TAG: 'INVALID_TARGET_TAG'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a dependency value to its numeric parent task ID.
|
||||||
|
* - Numbers are returned as-is (if finite)
|
||||||
|
* - Numeric strings are parsed ("5" -> 5)
|
||||||
|
* - Dotted strings return the parent portion ("5.2" -> 5)
|
||||||
|
* - Empty/invalid values return null
|
||||||
|
* - null/undefined are preserved
|
||||||
|
* @param {number|string|null|undefined} dep
|
||||||
|
* @returns {number|null|undefined}
|
||||||
|
*/
|
||||||
|
function normalizeDependency(dep) {
|
||||||
|
if (dep === null || dep === undefined) return dep;
|
||||||
|
if (typeof dep === 'number') return Number.isFinite(dep) ? dep : null;
|
||||||
|
if (typeof dep === 'string') {
|
||||||
|
const trimmed = dep.trim();
|
||||||
|
if (trimmed === '') return null;
|
||||||
|
const parentPart = trimmed.includes('.') ? trimmed.split('.')[0] : trimmed;
|
||||||
|
const parsed = parseInt(parentPart, 10);
|
||||||
|
return Number.isFinite(parsed) ? parsed : null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize an array of dependency values to numeric IDs.
|
||||||
|
* Preserves null/undefined input (returns as-is) and filters out invalid entries.
|
||||||
|
* @param {Array<any>|null|undefined} deps
|
||||||
|
* @returns {Array<number>|null|undefined}
|
||||||
|
*/
|
||||||
|
function normalizeDependencies(deps) {
|
||||||
|
if (deps === null || deps === undefined) return deps;
|
||||||
|
if (!Array.isArray(deps)) return deps;
|
||||||
|
return deps
|
||||||
|
.map((d) => normalizeDependency(d))
|
||||||
|
.filter((n) => Number.isFinite(n));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move one or more tasks/subtasks to new positions
|
* Move one or more tasks/subtasks to new positions
|
||||||
* @param {string} tasksPath - Path to tasks.json file
|
* @param {string} tasksPath - Path to tasks.json file
|
||||||
@@ -674,15 +711,34 @@ async function resolveDependencies(
|
|||||||
) {
|
) {
|
||||||
const { withDependencies = false, ignoreDependencies = false } = options;
|
const { withDependencies = false, ignoreDependencies = false } = options;
|
||||||
|
|
||||||
|
// Scope allTasks to the source tag to avoid cross-tag contamination when
|
||||||
|
// computing dependency chains for --with-dependencies
|
||||||
|
const tasksInSourceTag = Array.isArray(allTasks)
|
||||||
|
? allTasks.filter((t) => t && t.tag === sourceTag)
|
||||||
|
: [];
|
||||||
|
|
||||||
// Handle --with-dependencies flag first (regardless of cross-tag dependencies)
|
// Handle --with-dependencies flag first (regardless of cross-tag dependencies)
|
||||||
if (withDependencies) {
|
if (withDependencies) {
|
||||||
// Move dependent tasks along with main tasks
|
// Move dependent tasks along with main tasks
|
||||||
// Find ALL dependencies recursively within the same tag
|
// Find ALL dependencies recursively, but only using tasks from the source tag
|
||||||
const allDependentTaskIds = findAllDependenciesRecursively(
|
const allDependentTaskIdsRaw = findAllDependenciesRecursively(
|
||||||
sourceTasks,
|
sourceTasks,
|
||||||
allTasks,
|
tasksInSourceTag,
|
||||||
{ maxDepth: 100, includeSelf: false }
|
{ maxDepth: 100, includeSelf: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Filter dependent IDs to those that actually exist in the source tag
|
||||||
|
const sourceTagIds = new Set(
|
||||||
|
tasksInSourceTag.map((t) =>
|
||||||
|
typeof t.id === 'string' ? parseInt(t.id, 10) : t.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const allDependentTaskIds = allDependentTaskIdsRaw.filter((depId) => {
|
||||||
|
// Only numeric task IDs are eligible to be moved (subtasks cannot be moved cross-tag)
|
||||||
|
const normalizedId = normalizeDependency(depId);
|
||||||
|
return Number.isFinite(normalizedId) && sourceTagIds.has(normalizedId);
|
||||||
|
});
|
||||||
|
|
||||||
const allTaskIdsToMove = [...new Set([...taskIds, ...allDependentTaskIds])];
|
const allTaskIdsToMove = [...new Set([...taskIds, ...allDependentTaskIds])];
|
||||||
|
|
||||||
log(
|
log(
|
||||||
@@ -711,22 +767,31 @@ async function resolveDependencies(
|
|||||||
if (ignoreDependencies) {
|
if (ignoreDependencies) {
|
||||||
// Break cross-tag dependencies (edge case - shouldn't normally happen)
|
// Break cross-tag dependencies (edge case - shouldn't normally happen)
|
||||||
sourceTasks.forEach((task) => {
|
sourceTasks.forEach((task) => {
|
||||||
|
const sourceTagTasks = tasksInSourceTag;
|
||||||
|
const targetTagTasks = Array.isArray(allTasks)
|
||||||
|
? allTasks.filter((t) => t && t.tag === targetTag)
|
||||||
|
: [];
|
||||||
task.dependencies = task.dependencies.filter((depId) => {
|
task.dependencies = task.dependencies.filter((depId) => {
|
||||||
// Handle both task IDs and subtask IDs (e.g., "1.2")
|
const parentTaskId = normalizeDependency(depId);
|
||||||
let depTask = null;
|
|
||||||
if (typeof depId === 'string' && depId.includes('.')) {
|
// If dependency resolves to a task in the source tag, drop it (would be cross-tag after move)
|
||||||
// It's a subtask ID - extract parent task ID and find the parent task
|
if (
|
||||||
const [parentId, subtaskId] = depId
|
Number.isFinite(parentTaskId) &&
|
||||||
.split('.')
|
sourceTagTasks.some((t) => t.id === parentTaskId)
|
||||||
.map((id) => parseInt(id, 10));
|
) {
|
||||||
depTask = allTasks.find((t) => t.id === parentId);
|
return false;
|
||||||
} else {
|
|
||||||
// It's a regular task ID - normalize to number for comparison
|
|
||||||
const normalizedDepId =
|
|
||||||
typeof depId === 'string' ? parseInt(depId, 10) : depId;
|
|
||||||
depTask = allTasks.find((t) => t.id === normalizedDepId);
|
|
||||||
}
|
}
|
||||||
return !depTask || depTask.tag === targetTag;
|
|
||||||
|
// If dependency resolves to a task in the target tag, keep it
|
||||||
|
if (
|
||||||
|
Number.isFinite(parentTaskId) &&
|
||||||
|
targetTagTasks.some((t) => t.id === parentTaskId)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, keep as-is (unknown/unresolved dependency)
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -810,7 +875,16 @@ async function executeMoveOperation(
|
|||||||
if (existingTaskIndex !== -1) {
|
if (existingTaskIndex !== -1) {
|
||||||
throw new MoveTaskError(
|
throw new MoveTaskError(
|
||||||
MOVE_ERROR_CODES.TASK_ALREADY_EXISTS,
|
MOVE_ERROR_CODES.TASK_ALREADY_EXISTS,
|
||||||
`Task ${taskId} already exists in target tag "${targetTag}"`
|
`Task ${taskId} already exists in target tag "${targetTag}"`,
|
||||||
|
{
|
||||||
|
conflictingId: normalizedTaskId,
|
||||||
|
targetTag,
|
||||||
|
suggestions: [
|
||||||
|
'Choose a different target tag without conflicting IDs',
|
||||||
|
'Move a different set of IDs (avoid existing ones)',
|
||||||
|
'If needed, move within-tag to a new ID first, then cross-tag move'
|
||||||
|
]
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,7 +925,8 @@ async function finalizeMove(
|
|||||||
tasksPath,
|
tasksPath,
|
||||||
context,
|
context,
|
||||||
sourceTag,
|
sourceTag,
|
||||||
targetTag
|
targetTag,
|
||||||
|
dependencyResolution
|
||||||
) {
|
) {
|
||||||
const { projectRoot } = context;
|
const { projectRoot } = context;
|
||||||
const { rawData, movedTasks } = moveResult;
|
const { rawData, movedTasks } = moveResult;
|
||||||
@@ -859,10 +934,23 @@ async function finalizeMove(
|
|||||||
// Write the updated data
|
// Write the updated data
|
||||||
writeJSON(tasksPath, rawData, projectRoot, null);
|
writeJSON(tasksPath, rawData, projectRoot, null);
|
||||||
|
|
||||||
return {
|
const response = {
|
||||||
message: `Successfully moved ${movedTasks.length} tasks from "${sourceTag}" to "${targetTag}"`,
|
message: `Successfully moved ${movedTasks.length} tasks from "${sourceTag}" to "${targetTag}"`,
|
||||||
movedTasks
|
movedTasks
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If we intentionally broke cross-tag dependencies, provide tips to validate & fix
|
||||||
|
if (
|
||||||
|
dependencyResolution &&
|
||||||
|
dependencyResolution.type === 'ignored-dependencies'
|
||||||
|
) {
|
||||||
|
response.tips = [
|
||||||
|
'Run "task-master validate-dependencies" to check for dependency issues.',
|
||||||
|
'Run "task-master fix-dependencies" to automatically repair dangling dependencies.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -898,7 +986,7 @@ async function moveTasksBetweenTags(
|
|||||||
const { rawData, sourceTasks, allTasks } = await prepareTaskData(validation);
|
const { rawData, sourceTasks, allTasks } = await prepareTaskData(validation);
|
||||||
|
|
||||||
// 3. Handle dependencies
|
// 3. Handle dependencies
|
||||||
const { tasksToMove } = await resolveDependencies(
|
const { tasksToMove, dependencyResolution } = await resolveDependencies(
|
||||||
sourceTasks,
|
sourceTasks,
|
||||||
allTasks,
|
allTasks,
|
||||||
options,
|
options,
|
||||||
@@ -923,7 +1011,8 @@ async function moveTasksBetweenTags(
|
|||||||
tasksPath,
|
tasksPath,
|
||||||
context,
|
context,
|
||||||
sourceTag,
|
sourceTag,
|
||||||
targetTag
|
targetTag,
|
||||||
|
dependencyResolution
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import { z } from 'zod';
|
|||||||
import { TASK_PRIORITY_OPTIONS } from '../../../../src/constants/task-priority.js';
|
import { TASK_PRIORITY_OPTIONS } from '../../../../src/constants/task-priority.js';
|
||||||
import { getCurrentTag, isSilentMode, log } from '../../utils.js';
|
import { getCurrentTag, isSilentMode, log } from '../../utils.js';
|
||||||
import { Duration } from '../../../../src/utils/timeout-manager.js';
|
import { Duration } from '../../../../src/utils/timeout-manager.js';
|
||||||
import { CUSTOM_PROVIDERS } from '../../../../src/constants/providers.js';
|
import { hasCodebaseAnalysis } from '../../config-manager.js';
|
||||||
import { getMainProvider, getResearchProvider } from '../../config-manager.js';
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// SCHEMAS
|
// SCHEMAS
|
||||||
@@ -75,13 +74,10 @@ export class PrdParseConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if Claude Code is being used
|
* Check if codebase analysis is available (Claude Code or Gemini CLI)
|
||||||
*/
|
*/
|
||||||
isClaudeCode() {
|
hasCodebaseAnalysis() {
|
||||||
const currentProvider = this.research
|
return hasCodebaseAnalysis(this.research, this.projectRoot, this.session);
|
||||||
? getResearchProvider(this.projectRoot)
|
|
||||||
: getMainProvider(this.projectRoot);
|
|
||||||
return currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import path from 'path';
|
|||||||
import boxen from 'boxen';
|
import boxen from 'boxen';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { ensureTagMetadata, findTaskById } from '../../utils.js';
|
import { ensureTagMetadata, findTaskById } from '../../utils.js';
|
||||||
import { getPriorityIndicators } from '../../../../src/ui/indicators.js';
|
|
||||||
import { displayParsePrdSummary } from '../../../../src/ui/parse-prd.js';
|
import { displayParsePrdSummary } from '../../../../src/ui/parse-prd.js';
|
||||||
import { TimeoutManager } from '../../../../src/utils/timeout-manager.js';
|
import { TimeoutManager } from '../../../../src/utils/timeout-manager.js';
|
||||||
import { displayAiUsageSummary } from '../../ui.js';
|
import { displayAiUsageSummary } from '../../ui.js';
|
||||||
@@ -242,7 +241,7 @@ export async function buildPrompts(config, prdContent, nextId) {
|
|||||||
prdContent,
|
prdContent,
|
||||||
prdPath: config.prdPath,
|
prdPath: config.prdPath,
|
||||||
defaultTaskPriority,
|
defaultTaskPriority,
|
||||||
isClaudeCode: config.isClaudeCode(),
|
hasCodebaseAnalysis: config.hasCodebaseAnalysis(),
|
||||||
projectRoot: config.projectRoot || ''
|
projectRoot: config.projectRoot || ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
flattenTasksWithSubtasks
|
flattenTasksWithSubtasks
|
||||||
} from '../utils.js';
|
} from '../utils.js';
|
||||||
import { generateTextService } from '../ai-services-unified.js';
|
import { generateTextService } from '../ai-services-unified.js';
|
||||||
import { getDebugFlag } from '../config-manager.js';
|
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
import { ContextGatherer } from '../utils/contextGatherer.js';
|
import { ContextGatherer } from '../utils/contextGatherer.js';
|
||||||
@@ -231,7 +231,13 @@ async function updateSubtaskById(
|
|||||||
currentDetails: subtask.details || '(No existing details)',
|
currentDetails: subtask.details || '(No existing details)',
|
||||||
updatePrompt: prompt,
|
updatePrompt: prompt,
|
||||||
useResearch: useResearch,
|
useResearch: useResearch,
|
||||||
gatheredContext: gatheredContext || ''
|
gatheredContext: gatheredContext || '',
|
||||||
|
hasCodebaseAnalysis: hasCodebaseAnalysis(
|
||||||
|
useResearch,
|
||||||
|
projectRoot,
|
||||||
|
session
|
||||||
|
),
|
||||||
|
projectRoot: projectRoot
|
||||||
};
|
};
|
||||||
|
|
||||||
const variantKey = useResearch ? 'research' : 'default';
|
const variantKey = useResearch ? 'research' : 'default';
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ import {
|
|||||||
} from '../ui.js';
|
} from '../ui.js';
|
||||||
|
|
||||||
import { generateTextService } from '../ai-services-unified.js';
|
import { generateTextService } from '../ai-services-unified.js';
|
||||||
import { getDebugFlag, isApiKeySet } from '../config-manager.js';
|
import {
|
||||||
|
getDebugFlag,
|
||||||
|
isApiKeySet,
|
||||||
|
hasCodebaseAnalysis
|
||||||
|
} from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import { ContextGatherer } from '../utils/contextGatherer.js';
|
import { ContextGatherer } from '../utils/contextGatherer.js';
|
||||||
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
|
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
|
||||||
@@ -453,7 +457,13 @@ async function updateTaskById(
|
|||||||
appendMode: appendMode,
|
appendMode: appendMode,
|
||||||
useResearch: useResearch,
|
useResearch: useResearch,
|
||||||
currentDetails: taskToUpdate.details || '(No existing details)',
|
currentDetails: taskToUpdate.details || '(No existing details)',
|
||||||
gatheredContext: gatheredContext || ''
|
gatheredContext: gatheredContext || '',
|
||||||
|
hasCodebaseAnalysis: hasCodebaseAnalysis(
|
||||||
|
useResearch,
|
||||||
|
projectRoot,
|
||||||
|
session
|
||||||
|
),
|
||||||
|
projectRoot: projectRoot
|
||||||
};
|
};
|
||||||
|
|
||||||
const variantKey = appendMode
|
const variantKey = appendMode
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
displayAiUsageSummary
|
displayAiUsageSummary
|
||||||
} from '../ui.js';
|
} from '../ui.js';
|
||||||
|
|
||||||
import { getDebugFlag } from '../config-manager.js';
|
import { getDebugFlag, hasCodebaseAnalysis } from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
import { generateTextService } from '../ai-services-unified.js';
|
import { generateTextService } from '../ai-services-unified.js';
|
||||||
@@ -435,7 +435,13 @@ async function updateTasks(
|
|||||||
tasks: tasksToUpdate,
|
tasks: tasksToUpdate,
|
||||||
updatePrompt: prompt,
|
updatePrompt: prompt,
|
||||||
useResearch,
|
useResearch,
|
||||||
projectContext: gatheredContext
|
projectContext: gatheredContext,
|
||||||
|
hasCodebaseAnalysis: hasCodebaseAnalysis(
|
||||||
|
useResearch,
|
||||||
|
projectRoot,
|
||||||
|
session
|
||||||
|
),
|
||||||
|
projectRoot: projectRoot
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// --- End Build Prompts ---
|
// --- End Build Prompts ---
|
||||||
|
|||||||
@@ -2876,9 +2876,6 @@ export function displayCrossTagDependencyError(
|
|||||||
` 4. Move dependencies first: task-master move --from=${conflicts.map((c) => c.dependencyId).join(',')} --from-tag=${conflicts[0].dependencyTag} --to-tag=${targetTag}`
|
` 4. Move dependencies first: task-master move --from=${conflicts.map((c) => c.dependencyId).join(',')} --from-tag=${conflicts[0].dependencyTag} --to-tag=${targetTag}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log(
|
|
||||||
` 5. Force move (may break dependencies): task-master move --from=${sourceIds} --from-tag=${sourceTag} --to-tag=${targetTag} --force`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -45,12 +45,24 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Use research mode"
|
"description": "Use research mode"
|
||||||
|
},
|
||||||
|
"hasCodebaseAnalysis": {
|
||||||
|
"type": "boolean",
|
||||||
|
"required": false,
|
||||||
|
"default": false,
|
||||||
|
"description": "Whether codebase analysis is available"
|
||||||
|
},
|
||||||
|
"projectRoot": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false,
|
||||||
|
"default": "",
|
||||||
|
"description": "Project root path for context"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"default": {
|
"default": {
|
||||||
"system": "You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\nWhen determining dependencies for a new task, follow these principles:\n1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n2. Prioritize task dependencies that are semantically related to the functionality being built.\n3. Consider both direct dependencies (immediately prerequisite) and indirect dependencies.\n4. Avoid adding unnecessary dependencies - only include tasks that are genuinely prerequisite.\n5. Consider the current status of tasks - prefer completed tasks as dependencies when possible.\n6. Pay special attention to foundation tasks (1-5) but don't automatically include them without reason.\n7. Recent tasks (higher ID numbers) may be more relevant for newer functionality.\n\nThe dependencies array should contain task IDs (numbers) of prerequisite tasks.{{#if useResearch}}\n\nResearch current best practices and technologies relevant to this task.{{/if}}",
|
"system": "You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\nWhen determining dependencies for a new task, follow these principles:\n1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n2. Prioritize task dependencies that are semantically related to the functionality being built.\n3. Consider both direct dependencies (immediately prerequisite) and indirect dependencies.\n4. Avoid adding unnecessary dependencies - only include tasks that are genuinely prerequisite.\n5. Consider the current status of tasks - prefer completed tasks as dependencies when possible.\n6. Pay special attention to foundation tasks (1-5) but don't automatically include them without reason.\n7. Recent tasks (higher ID numbers) may be more relevant for newer functionality.\n\nThe dependencies array should contain task IDs (numbers) of prerequisite tasks.{{#if useResearch}}\n\nResearch current best practices and technologies relevant to this task.{{/if}}",
|
||||||
"user": "You are generating the details for Task #{{newTaskId}}. Based on the user's request: \"{{prompt}}\", create a comprehensive new task for a software development project.\n \n {{gatheredContext}}\n \n {{#if useResearch}}Research current best practices, technologies, and implementation patterns relevant to this task. {{/if}}Based on the information about existing tasks provided above, include appropriate dependencies in the \"dependencies\" array. Only include task IDs that this new task directly depends on.\n \n Return your answer as a single JSON object matching the schema precisely:\n \n {\n \"title\": \"Task title goes here\",\n \"description\": \"A concise one or two sentence description of what the task involves\",\n \"details\": \"Detailed implementation steps, considerations, code examples, or technical approach\",\n \"testStrategy\": \"Specific steps to verify correct implementation and functionality\",\n \"dependencies\": [1, 3] // Example: IDs of tasks that must be completed before this task\n }\n \n Make sure the details and test strategy are comprehensive and specific{{#if useResearch}}, incorporating current best practices from your research{{/if}}. DO NOT include the task ID in the title.\n {{#if contextFromArgs}}{{contextFromArgs}}{{/if}}"
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating the task:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine key files like package.json, main entry points, and relevant source files\n4. Analyze the current implementation to understand what already exists\n\nBased on your analysis:\n- Identify existing components/features that relate to this new task\n- Understand the technology stack, frameworks, and patterns in use\n- Generate implementation details that align with the project's current architecture\n- Reference specific files, functions, or patterns from the codebase in your details\n\nProject Root: {{projectRoot}}\n\n{{/if}}You are generating the details for Task #{{newTaskId}}. Based on the user's request: \"{{prompt}}\", create a comprehensive new task for a software development project.\n \n {{gatheredContext}}\n \n {{#if useResearch}}Research current best practices, technologies, and implementation patterns relevant to this task. {{/if}}Based on the information about existing tasks provided above, include appropriate dependencies in the \"dependencies\" array. Only include task IDs that this new task directly depends on.\n \n Return your answer as a single JSON object matching the schema precisely:\n \n {\n \"title\": \"Task title goes here\",\n \"description\": \"A concise one or two sentence description of what the task involves\",\n \"details\": \"Detailed implementation steps, considerations, code examples, or technical approach\",\n \"testStrategy\": \"Specific steps to verify correct implementation and functionality\",\n \"dependencies\": [1, 3] // Example: IDs of tasks that must be completed before this task\n }\n \n Make sure the details and test strategy are comprehensive and specific{{#if useResearch}}, incorporating current best practices from your research{{/if}}. DO NOT include the task ID in the title.\n {{#if contextFromArgs}}{{contextFromArgs}}{{/if}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,10 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Use research mode for deeper analysis"
|
"description": "Use research mode for deeper analysis"
|
||||||
},
|
},
|
||||||
"isClaudeCode": {
|
"hasCodebaseAnalysis": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Whether Claude Code is being used as the provider"
|
"description": "Whether codebase analysis is available"
|
||||||
},
|
},
|
||||||
"projectRoot": {
|
"projectRoot": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
"prompts": {
|
"prompts": {
|
||||||
"default": {
|
"default": {
|
||||||
"system": "You are an expert software architect and project manager analyzing task complexity. Respond only with the requested valid JSON array.",
|
"system": "You are an expert software architect and project manager analyzing task complexity. Respond only with the requested valid JSON array.",
|
||||||
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before analyzing task complexity:\n\n1. Use the Glob tool to explore the project structure and understand the codebase size\n2. Use the Grep tool to search for existing implementations related to each task\n3. Use the Read tool to examine key files that would be affected by these tasks\n4. Understand the current implementation state, patterns used, and technical debt\n\nBased on your codebase analysis:\n- Assess complexity based on ACTUAL code that needs to be modified/created\n- Consider existing abstractions and patterns that could simplify implementation\n- Identify tasks that require refactoring vs. greenfield development\n- Factor in dependencies between existing code and new features\n- Provide more accurate subtask recommendations based on real code structure\n\nProject Root: {{projectRoot}}\n\n{{/if}}Analyze the following tasks to determine their complexity (1-10 scale) and recommend the number of subtasks for expansion. Provide a brief reasoning and an initial expansion prompt for each.{{#if useResearch}} Consider current best practices, common implementation patterns, and industry standards in your analysis.{{/if}}\n\nTasks:\n{{{json tasks}}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n\nRespond ONLY with a valid JSON array matching the schema:\n[\n {\n \"taskId\": <number>,\n \"taskTitle\": \"<string>\",\n \"complexityScore\": <number 1-10>,\n \"recommendedSubtasks\": <number>,\n \"expansionPrompt\": \"<string>\",\n \"reasoning\": \"<string>\"\n },\n ...\n]\n\nDo not include any explanatory text, markdown formatting, or code block markers before or after the JSON array."
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before analyzing task complexity:\n\n1. Use the Glob tool to explore the project structure and understand the codebase size\n2. Use the Grep tool to search for existing implementations related to each task\n3. Use the Read tool to examine key files that would be affected by these tasks\n4. Understand the current implementation state, patterns used, and technical debt\n\nBased on your codebase analysis:\n- Assess complexity based on ACTUAL code that needs to be modified/created\n- Consider existing abstractions and patterns that could simplify implementation\n- Identify tasks that require refactoring vs. greenfield development\n- Factor in dependencies between existing code and new features\n- Provide more accurate subtask recommendations based on real code structure\n\nProject Root: {{projectRoot}}\n\n{{/if}}Analyze the following tasks to determine their complexity (1-10 scale) and recommend the number of subtasks for expansion. Provide a brief reasoning and an initial expansion prompt for each.{{#if useResearch}} Consider current best practices, common implementation patterns, and industry standards in your analysis.{{/if}}\n\nTasks:\n{{{json tasks}}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n\nRespond ONLY with a valid JSON array matching the schema:\n[\n {\n \"taskId\": <number>,\n \"taskTitle\": \"<string>\",\n \"complexityScore\": <number 1-10>,\n \"recommendedSubtasks\": <number>,\n \"expansionPrompt\": \"<string>\",\n \"reasoning\": \"<string>\"\n },\n ...\n]\n\nDo not include any explanatory text, markdown formatting, or code block markers before or after the JSON array."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,11 @@
|
|||||||
"default": "",
|
"default": "",
|
||||||
"description": "Gathered project context"
|
"description": "Gathered project context"
|
||||||
},
|
},
|
||||||
"isClaudeCode": {
|
"hasCodebaseAnalysis": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"required": false,
|
"required": false,
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Whether Claude Code is being used as the provider"
|
"description": "Whether codebase analysis is available"
|
||||||
},
|
},
|
||||||
"projectRoot": {
|
"projectRoot": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -74,11 +74,11 @@
|
|||||||
"research": {
|
"research": {
|
||||||
"condition": "useResearch === true && !expansionPrompt",
|
"condition": "useResearch === true && !expansionPrompt",
|
||||||
"system": "You are an AI assistant that responds ONLY with valid JSON objects as requested. The object should contain a 'subtasks' array.",
|
"system": "You are an AI assistant that responds ONLY with valid JSON objects as requested. The object should contain a 'subtasks' array.",
|
||||||
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}Analyze the following task and break it down into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks using your research capabilities. Assign sequential IDs starting from {{nextSubtaskId}}.\n\nParent Task:\nID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nConsider this context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nCRITICAL: Respond ONLY with a valid JSON object containing a single key \"subtasks\". The value must be an array of the generated subtasks, strictly matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": <number>, // Sequential ID starting from {{nextSubtaskId}}\n \"title\": \"<string>\",\n \"description\": \"<string>\",\n \"dependencies\": [\"<string>\"], // Use full subtask IDs like [\"{{task.id}}.1\", \"{{task.id}}.2\"]. If no dependencies, use an empty array [].\n \"details\": \"<string>\",\n \"testStrategy\": \"<string>\" // Optional\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}appropriate number of{{/if}} subtasks)\n ]\n}\n\nImportant: For the 'dependencies' field, if a subtask has no dependencies, you MUST use an empty array, for example: \"dependencies\": []. Do not use null or omit the field.\n\nDo not include ANY explanatory text, markdown, or code block markers. Just the JSON object."
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}Analyze the following task and break it down into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks using your research capabilities. Assign sequential IDs starting from {{nextSubtaskId}}.\n\nParent Task:\nID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nConsider this context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nCRITICAL: Respond ONLY with a valid JSON object containing a single key \"subtasks\". The value must be an array of the generated subtasks, strictly matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": <number>, // Sequential ID starting from {{nextSubtaskId}}\n \"title\": \"<string>\",\n \"description\": \"<string>\",\n \"dependencies\": [\"<string>\"], // Use full subtask IDs like [\"{{task.id}}.1\", \"{{task.id}}.2\"]. If no dependencies, use an empty array [].\n \"details\": \"<string>\",\n \"testStrategy\": \"<string>\" // Optional\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}appropriate number of{{/if}} subtasks)\n ]\n}\n\nImportant: For the 'dependencies' field, if a subtask has no dependencies, you MUST use an empty array, for example: \"dependencies\": []. Do not use null or omit the field.\n\nDo not include ANY explanatory text, markdown, or code block markers. Just the JSON object."
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"system": "You are an AI assistant helping with task breakdown for software development.\nYou need to break down a high-level task into {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks that can be implemented one by one.\n\nSubtasks should:\n1. Be specific and actionable implementation steps\n2. Follow a logical sequence\n3. Each handle a distinct part of the parent task\n4. Include clear guidance on implementation approach\n5. Have appropriate dependency chains between subtasks (using full subtask IDs)\n6. Collectively cover all aspects of the parent task\n\nFor each subtask, provide:\n- id: Sequential integer starting from the provided nextSubtaskId\n- title: Clear, specific title\n- description: Detailed description\n- dependencies: Array of prerequisite subtask IDs using full format like [\"{{task.id}}.1\", \"{{task.id}}.2\"]\n- details: Implementation details, the output should be in string\n- testStrategy: Optional testing approach\n\nRespond ONLY with a valid JSON object containing a single key \"subtasks\" whose value is an array matching the structure described. Do not include any explanatory text, markdown formatting, or code block markers.",
|
"system": "You are an AI assistant helping with task breakdown for software development.\nYou need to break down a high-level task into {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks that can be implemented one by one.\n\nSubtasks should:\n1. Be specific and actionable implementation steps\n2. Follow a logical sequence\n3. Each handle a distinct part of the parent task\n4. Include clear guidance on implementation approach\n5. Have appropriate dependency chains between subtasks (using full subtask IDs)\n6. Collectively cover all aspects of the parent task\n\nFor each subtask, provide:\n- id: Sequential integer starting from the provided nextSubtaskId\n- title: Clear, specific title\n- description: Detailed description\n- dependencies: Array of prerequisite subtask IDs using full format like [\"{{task.id}}.1\", \"{{task.id}}.2\"]\n- details: Implementation details, the output should be in string\n- testStrategy: Optional testing approach\n\nRespond ONLY with a valid JSON object containing a single key \"subtasks\" whose value is an array matching the structure described. Do not include any explanatory text, markdown formatting, or code block markers.",
|
||||||
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}Break down this task into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks:\n\nTask ID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nAdditional context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nReturn ONLY the JSON object containing the \"subtasks\" array, matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": {{nextSubtaskId}}, // First subtask ID\n \"title\": \"Specific subtask title\",\n \"description\": \"Detailed description\",\n \"dependencies\": [], // e.g., [\"{{task.id}}.1\", \"{{task.id}}.2\"] for dependencies. Use empty array [] if no dependencies\n \"details\": \"Implementation guidance\",\n \"testStrategy\": \"Optional testing approach\"\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}a total of {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks with sequential IDs)\n ]\n}"
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}Break down this task into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks:\n\nTask ID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nAdditional context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nReturn ONLY the JSON object containing the \"subtasks\" array, matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": {{nextSubtaskId}}, // First subtask ID\n \"title\": \"Specific subtask title\",\n \"description\": \"Detailed description\",\n \"dependencies\": [], // e.g., [\"{{task.id}}.1\", \"{{task.id}}.2\"] for dependencies. Use empty array [] if no dependencies\n \"details\": \"Implementation guidance\",\n \"testStrategy\": \"Optional testing approach\"\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}a total of {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks with sequential IDs)\n ]\n}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,11 @@
|
|||||||
"enum": ["high", "medium", "low"],
|
"enum": ["high", "medium", "low"],
|
||||||
"description": "Default priority for generated tasks"
|
"description": "Default priority for generated tasks"
|
||||||
},
|
},
|
||||||
"isClaudeCode": {
|
"hasCodebaseAnalysis": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"required": false,
|
"required": false,
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Whether Claude Code is being used as the provider"
|
"description": "Whether codebase analysis is available"
|
||||||
},
|
},
|
||||||
"projectRoot": {
|
"projectRoot": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
"prompts": {
|
"prompts": {
|
||||||
"default": {
|
"default": {
|
||||||
"system": "You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format.{{#if research}}\nBefore breaking down the PRD into tasks, you will:\n1. Research and analyze the latest technologies, libraries, frameworks, and best practices that would be appropriate for this project\n2. Identify any potential technical challenges, security concerns, or scalability issues not explicitly mentioned in the PRD without discarding any explicit requirements or going overboard with complexity -- always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches\n3. Consider current industry standards and evolving trends relevant to this project (this step aims to solve LLM hallucinations and out of date information due to training data cutoff dates)\n4. Evaluate alternative implementation approaches and recommend the most efficient path\n5. Include specific library versions, helpful APIs, and concrete implementation guidance based on your research\n6. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches\n\nYour task breakdown should incorporate this research, resulting in more detailed implementation guidance, more accurate dependency mapping, and more precise technology recommendations than would be possible from the PRD text alone, while maintaining all explicit requirements and best practices and all details and nuances of the PRD.{{/if}}\n\nAnalyze the provided PRD content and generate {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} top-level development tasks. If the complexity or the level of detail of the PRD is high, generate more tasks relative to the complexity of the PRD\nEach task should represent a logical unit of work needed to implement the requirements and focus on the most direct and effective way to implement the requirements without unnecessary complexity or overengineering. Include pseudo-code, implementation details, and test strategy for each task. Find the most up to date information to implement each task.\nAssign sequential IDs starting from {{nextId}}. Infer title, description, details, and test strategy for each task based *only* on the PRD content.\nSet status to 'pending', dependencies to an empty array [], and priority to '{{defaultTaskPriority}}' initially for all tasks.\nRespond ONLY with a valid JSON object containing a single key \"tasks\", where the value is an array of task objects adhering to the provided Zod schema. Do not include any explanation or markdown formatting.\n\nEach task should follow this JSON structure:\n{\n\t\"id\": number,\n\t\"title\": string,\n\t\"description\": string,\n\t\"status\": \"pending\",\n\t\"dependencies\": number[] (IDs of tasks this depends on),\n\t\"priority\": \"high\" | \"medium\" | \"low\",\n\t\"details\": string (implementation details),\n\t\"testStrategy\": string (validation approach)\n}\n\nGuidelines:\n1. {{#if (gt numTasks 0)}}Unless complexity warrants otherwise{{else}}Depending on the complexity{{/if}}, create {{#if (gt numTasks 0)}}exactly {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, numbered sequentially starting from {{nextId}}\n2. Each task should be atomic and focused on a single responsibility following the most up to date best practices and standards\n3. Order tasks logically - consider dependencies and implementation sequence\n4. Early tasks should focus on setup, core functionality first, then advanced features\n5. Include clear validation/testing approach for each task\n6. Set appropriate dependency IDs (a task can only depend on tasks with lower IDs, potentially including existing tasks with IDs less than {{nextId}} if applicable)\n7. Assign priority (high/medium/low) based on criticality and dependency order\n8. Include detailed implementation guidance in the \"details\" field{{#if research}}, with specific libraries and version recommendations based on your research{{/if}}\n9. If the PRD contains specific requirements for libraries, database schemas, frameworks, tech stacks, or any other implementation details, STRICTLY ADHERE to these requirements in your task breakdown and do not discard them under any circumstance\n10. Focus on filling in any gaps left by the PRD or areas that aren't fully specified, while preserving all explicit requirements\n11. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches{{#if research}}\n12. For each task, include specific, actionable guidance based on current industry standards and best practices discovered through research{{/if}}",
|
"system": "You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format.{{#if research}}\nBefore breaking down the PRD into tasks, you will:\n1. Research and analyze the latest technologies, libraries, frameworks, and best practices that would be appropriate for this project\n2. Identify any potential technical challenges, security concerns, or scalability issues not explicitly mentioned in the PRD without discarding any explicit requirements or going overboard with complexity -- always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches\n3. Consider current industry standards and evolving trends relevant to this project (this step aims to solve LLM hallucinations and out of date information due to training data cutoff dates)\n4. Evaluate alternative implementation approaches and recommend the most efficient path\n5. Include specific library versions, helpful APIs, and concrete implementation guidance based on your research\n6. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches\n\nYour task breakdown should incorporate this research, resulting in more detailed implementation guidance, more accurate dependency mapping, and more precise technology recommendations than would be possible from the PRD text alone, while maintaining all explicit requirements and best practices and all details and nuances of the PRD.{{/if}}\n\nAnalyze the provided PRD content and generate {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} top-level development tasks. If the complexity or the level of detail of the PRD is high, generate more tasks relative to the complexity of the PRD\nEach task should represent a logical unit of work needed to implement the requirements and focus on the most direct and effective way to implement the requirements without unnecessary complexity or overengineering. Include pseudo-code, implementation details, and test strategy for each task. Find the most up to date information to implement each task.\nAssign sequential IDs starting from {{nextId}}. Infer title, description, details, and test strategy for each task based *only* on the PRD content.\nSet status to 'pending', dependencies to an empty array [], and priority to '{{defaultTaskPriority}}' initially for all tasks.\nRespond ONLY with a valid JSON object containing a single key \"tasks\", where the value is an array of task objects adhering to the provided Zod schema. Do not include any explanation or markdown formatting.\n\nEach task should follow this JSON structure:\n{\n\t\"id\": number,\n\t\"title\": string,\n\t\"description\": string,\n\t\"status\": \"pending\",\n\t\"dependencies\": number[] (IDs of tasks this depends on),\n\t\"priority\": \"high\" | \"medium\" | \"low\",\n\t\"details\": string (implementation details),\n\t\"testStrategy\": string (validation approach)\n}\n\nGuidelines:\n1. {{#if (gt numTasks 0)}}Unless complexity warrants otherwise{{else}}Depending on the complexity{{/if}}, create {{#if (gt numTasks 0)}}exactly {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, numbered sequentially starting from {{nextId}}\n2. Each task should be atomic and focused on a single responsibility following the most up to date best practices and standards\n3. Order tasks logically - consider dependencies and implementation sequence\n4. Early tasks should focus on setup, core functionality first, then advanced features\n5. Include clear validation/testing approach for each task\n6. Set appropriate dependency IDs (a task can only depend on tasks with lower IDs, potentially including existing tasks with IDs less than {{nextId}} if applicable)\n7. Assign priority (high/medium/low) based on criticality and dependency order\n8. Include detailed implementation guidance in the \"details\" field{{#if research}}, with specific libraries and version recommendations based on your research{{/if}}\n9. If the PRD contains specific requirements for libraries, database schemas, frameworks, tech stacks, or any other implementation details, STRICTLY ADHERE to these requirements in your task breakdown and do not discard them under any circumstance\n10. Focus on filling in any gaps left by the PRD or areas that aren't fully specified, while preserving all explicit requirements\n11. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches{{#if research}}\n12. For each task, include specific, actionable guidance based on current industry standards and best practices discovered through research{{/if}}",
|
||||||
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating tasks:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine key files like package.json, README.md, and main entry points\n4. Analyze the current state of implementation to understand what already exists\n\nBased on your analysis:\n- Identify what components/features are already implemented\n- Understand the technology stack, frameworks, and patterns in use\n- Generate tasks that build upon the existing codebase rather than duplicating work\n- Ensure tasks align with the project's current architecture and conventions\n\nProject Root: {{projectRoot}}\n\n{{/if}}Here's the Product Requirements Document (PRD) to break down into {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, starting IDs from {{nextId}}:{{#if research}}\n\nRemember to thoroughly research current best practices and technologies before task breakdown to provide specific, actionable implementation details.{{/if}}\n\n{{prdContent}}\n\n\n\t\tReturn your response in this format:\n{\n \"tasks\": [\n {\n \"id\": 1,\n \"title\": \"Setup Project Repository\",\n \"description\": \"...\",\n ...\n },\n ...\n ],\n \"metadata\": {\n \"projectName\": \"PRD Implementation\",\n \"totalTasks\": {{#if (gt numTasks 0)}}{{numTasks}}{{else}}{number of tasks}{{/if}},\n \"sourceFile\": \"{{prdPath}}\",\n \"generatedAt\": \"YYYY-MM-DD\"\n }\n}"
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating tasks:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine key files like package.json, README.md, and main entry points\n4. Analyze the current state of implementation to understand what already exists\n\nBased on your analysis:\n- Identify what components/features are already implemented\n- Understand the technology stack, frameworks, and patterns in use\n- Generate tasks that build upon the existing codebase rather than duplicating work\n- Ensure tasks align with the project's current architecture and conventions\n\nProject Root: {{projectRoot}}\n\n{{/if}}Here's the Product Requirements Document (PRD) to break down into {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, starting IDs from {{nextId}}:{{#if research}}\n\nRemember to thoroughly research current best practices and technologies before task breakdown to provide specific, actionable implementation details.{{/if}}\n\n{{prdContent}}\n\n\n\t\tReturn your response in this format:\n{\n \"tasks\": [\n {\n \"id\": 1,\n \"title\": \"Setup Project Repository\",\n \"description\": \"...\",\n ...\n },\n ...\n ],\n \"metadata\": {\n \"projectName\": \"PRD Implementation\",\n \"totalTasks\": {{#if (gt numTasks 0)}}{{numTasks}}{{else}}{number of tasks}{{/if}},\n \"sourceFile\": \"{{prdPath}}\",\n \"generatedAt\": \"YYYY-MM-DD\"\n }\n}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,24 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "Additional project context"
|
"description": "Additional project context"
|
||||||
|
},
|
||||||
|
"hasCodebaseAnalysis": {
|
||||||
|
"type": "boolean",
|
||||||
|
"required": false,
|
||||||
|
"default": false,
|
||||||
|
"description": "Whether codebase analysis is available"
|
||||||
|
},
|
||||||
|
"projectRoot": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false,
|
||||||
|
"default": "",
|
||||||
|
"description": "Project root path for context"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"default": {
|
"default": {
|
||||||
"system": "You are an AI assistant helping to update a subtask. You will be provided with the subtask's existing details, context about its parent and sibling tasks, and a user request string.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}\n\nYour Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the subtask's details.\nFocus *only* on generating the substance of the update.\n\nOutput Requirements:\n1. Return *only* the newly generated text content as a plain string. Do NOT return a JSON object or any other structured data.\n2. Your string response should NOT include any of the subtask's original details, unless the user's request explicitly asks to rephrase, summarize, or directly modify existing text.\n3. Do NOT include any timestamps, XML-like tags, markdown, or any other special formatting in your string response.\n4. Ensure the generated text is concise yet complete for the update based on the user request. Avoid conversational fillers or explanations about what you are doing (e.g., do not start with \"Okay, here's the update...\").{{#if useResearch}}\n5. Include specific libraries, versions, and current best practices relevant to the subtask implementation.\n6. Provide research-backed technical recommendations and proven approaches.{{/if}}",
|
"system": "You are an AI assistant helping to update a subtask. You will be provided with the subtask's existing details, context about its parent and sibling tasks, and a user request string.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}\n\nYour Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the subtask's details.\nFocus *only* on generating the substance of the update.\n\nOutput Requirements:\n1. Return *only* the newly generated text content as a plain string. Do NOT return a JSON object or any other structured data.\n2. Your string response should NOT include any of the subtask's original details, unless the user's request explicitly asks to rephrase, summarize, or directly modify existing text.\n3. Do NOT include any timestamps, XML-like tags, markdown, or any other special formatting in your string response.\n4. Ensure the generated text is concise yet complete for the update based on the user request. Avoid conversational fillers or explanations about what you are doing (e.g., do not start with \"Okay, here's the update...\").{{#if useResearch}}\n5. Include specific libraries, versions, and current best practices relevant to the subtask implementation.\n6. Provide research-backed technical recommendations and proven approaches.{{/if}}",
|
||||||
"user": "Task Context:\n\nParent Task: {{{json parentTask}}}\n{{#if prevSubtask}}Previous Subtask: {{{json prevSubtask}}}\n{{/if}}{{#if nextSubtask}}Next Subtask: {{{json nextSubtask}}}\n{{/if}}Current Subtask Details (for context only):\n{{currentDetails}}\n\nUser Request: \"{{updatePrompt}}\"\n\n{{#if useResearch}}Research and incorporate current best practices, latest stable versions, and proven approaches into your update. {{/if}}Based on the User Request and all the Task Context (including current subtask details provided above), what is the new information or text that should be appended to this subtask's details? Return ONLY this new text as a plain string.{{#if useResearch}} Include specific technical recommendations based on current industry standards.{{/if}}\n{{#if gatheredContext}}\n\n# Additional Project Context\n\n{{gatheredContext}}\n{{/if}}"
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating the subtask update:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine relevant files and understand current implementation\n4. Analyze the current codebase to inform your subtask update\n\nBased on your analysis:\n- Include specific file references, code patterns, or implementation details\n- Ensure suggestions align with the project's current architecture\n- Reference existing components or patterns when relevant\n- Make implementation notes specific to the codebase structure\n\nProject Root: {{projectRoot}}\n\n{{/if}}Task Context:\n\nParent Task: {{{json parentTask}}}\n{{#if prevSubtask}}Previous Subtask: {{{json prevSubtask}}}\n{{/if}}{{#if nextSubtask}}Next Subtask: {{{json nextSubtask}}}\n{{/if}}Current Subtask Details (for context only):\n{{currentDetails}}\n\nUser Request: \"{{updatePrompt}}\"\n\n{{#if useResearch}}Research and incorporate current best practices, latest stable versions, and proven approaches into your update. {{/if}}Based on the User Request and all the Task Context (including current subtask details provided above), what is the new information or text that should be appended to this subtask's details? Return ONLY this new text as a plain string.{{#if useResearch}} Include specific technical recommendations based on current industry standards.{{/if}}\n{{#if gatheredContext}}\n\n# Additional Project Context\n\n{{gatheredContext}}\n{{/if}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,17 +43,29 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "Additional project context"
|
"description": "Additional project context"
|
||||||
|
},
|
||||||
|
"hasCodebaseAnalysis": {
|
||||||
|
"type": "boolean",
|
||||||
|
"required": false,
|
||||||
|
"default": false,
|
||||||
|
"description": "Whether codebase analysis is available"
|
||||||
|
},
|
||||||
|
"projectRoot": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false,
|
||||||
|
"default": "",
|
||||||
|
"description": "Project root path for context"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"default": {
|
"default": {
|
||||||
"system": "You are an AI assistant helping to update a software development task based on new context.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}\nYou will be given a task and a prompt describing changes or new implementation details.\nYour job is to update the task to reflect these changes, while preserving its basic structure.\n\nGuidelines:\n1. VERY IMPORTANT: NEVER change the title of the task - keep it exactly as is\n2. Maintain the same ID, status, and dependencies unless specifically mentioned in the prompt{{#if useResearch}}\n3. Research and update the description, details, and test strategy with current best practices\n4. Include specific versions, libraries, and approaches that are current and well-tested{{/if}}{{#if (not useResearch)}}\n3. Update the description, details, and test strategy to reflect the new information\n4. Do not change anything unnecessarily - just adapt what needs to change based on the prompt{{/if}}\n5. Return a complete valid JSON object representing the updated task\n6. VERY IMPORTANT: Preserve all subtasks marked as \"done\" or \"completed\" - do not modify their content\n7. For tasks with completed subtasks, build upon what has already been done rather than rewriting everything\n8. If an existing completed subtask needs to be changed/undone based on the new context, DO NOT modify it directly\n9. Instead, add a new subtask that clearly indicates what needs to be changed or replaced\n10. Use the existence of completed subtasks as an opportunity to make new subtasks more specific and targeted\n11. Ensure any new subtasks have unique IDs that don't conflict with existing ones\n12. CRITICAL: For subtask IDs, use ONLY numeric values (1, 2, 3, etc.) NOT strings (\"1\", \"2\", \"3\")\n13. CRITICAL: Subtask IDs should start from 1 and increment sequentially (1, 2, 3...) - do NOT use parent task ID as prefix{{#if useResearch}}\n14. Include links to documentation or resources where helpful\n15. Focus on practical, implementable solutions using current technologies{{/if}}\n\nThe changes described in the prompt should be thoughtfully applied to make the task more accurate and actionable.",
|
"system": "You are an AI assistant helping to update a software development task based on new context.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}\nYou will be given a task and a prompt describing changes or new implementation details.\nYour job is to update the task to reflect these changes, while preserving its basic structure.\n\nGuidelines:\n1. VERY IMPORTANT: NEVER change the title of the task - keep it exactly as is\n2. Maintain the same ID, status, and dependencies unless specifically mentioned in the prompt{{#if useResearch}}\n3. Research and update the description, details, and test strategy with current best practices\n4. Include specific versions, libraries, and approaches that are current and well-tested{{/if}}{{#if (not useResearch)}}\n3. Update the description, details, and test strategy to reflect the new information\n4. Do not change anything unnecessarily - just adapt what needs to change based on the prompt{{/if}}\n5. Return a complete valid JSON object representing the updated task\n6. VERY IMPORTANT: Preserve all subtasks marked as \"done\" or \"completed\" - do not modify their content\n7. For tasks with completed subtasks, build upon what has already been done rather than rewriting everything\n8. If an existing completed subtask needs to be changed/undone based on the new context, DO NOT modify it directly\n9. Instead, add a new subtask that clearly indicates what needs to be changed or replaced\n10. Use the existence of completed subtasks as an opportunity to make new subtasks more specific and targeted\n11. Ensure any new subtasks have unique IDs that don't conflict with existing ones\n12. CRITICAL: For subtask IDs, use ONLY numeric values (1, 2, 3, etc.) NOT strings (\"1\", \"2\", \"3\")\n13. CRITICAL: Subtask IDs should start from 1 and increment sequentially (1, 2, 3...) - do NOT use parent task ID as prefix{{#if useResearch}}\n14. Include links to documentation or resources where helpful\n15. Focus on practical, implementable solutions using current technologies{{/if}}\n\nThe changes described in the prompt should be thoughtfully applied to make the task more accurate and actionable.",
|
||||||
"user": "Here is the task to update{{#if useResearch}} with research-backed information{{/if}}:\n{{{taskJson}}}\n\nPlease {{#if useResearch}}research and {{/if}}update this task based on the following {{#if useResearch}}context:\n{{updatePrompt}}\n\nIncorporate current best practices, latest stable versions, and proven approaches.{{/if}}{{#if (not useResearch)}}new context:\n{{updatePrompt}}{{/if}}\n\nIMPORTANT: {{#if useResearch}}Preserve any subtasks marked as \"done\" or \"completed\".{{/if}}{{#if (not useResearch)}}In the task JSON above, any subtasks with \"status\": \"done\" or \"status\": \"completed\" should be preserved exactly as is. Build your changes around these completed items.{{/if}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n\nReturn only the updated task as a valid JSON object{{#if useResearch}} with research-backed improvements{{/if}}."
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before updating the task:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine relevant files and understand current implementation\n4. Analyze how the task changes relate to the existing codebase\n\nBased on your analysis:\n- Update task details to reference specific files, functions, or patterns from the codebase\n- Ensure implementation details align with the project's current architecture\n- Include specific code examples or file references where appropriate\n- Consider how changes impact existing components\n\nProject Root: {{projectRoot}}\n\n{{/if}}Here is the task to update{{#if useResearch}} with research-backed information{{/if}}:\n{{{taskJson}}}\n\nPlease {{#if useResearch}}research and {{/if}}update this task based on the following {{#if useResearch}}context:\n{{updatePrompt}}\n\nIncorporate current best practices, latest stable versions, and proven approaches.{{/if}}{{#if (not useResearch)}}new context:\n{{updatePrompt}}{{/if}}\n\nIMPORTANT: {{#if useResearch}}Preserve any subtasks marked as \"done\" or \"completed\".{{/if}}{{#if (not useResearch)}}In the task JSON above, any subtasks with \"status\": \"done\" or \"status\": \"completed\" should be preserved exactly as is. Build your changes around these completed items.{{/if}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n\nReturn only the updated task as a valid JSON object{{#if useResearch}} with research-backed improvements{{/if}}."
|
||||||
},
|
},
|
||||||
"append": {
|
"append": {
|
||||||
"condition": "appendMode === true",
|
"condition": "appendMode === true",
|
||||||
"system": "You are an AI assistant helping to append additional information to a software development task. You will be provided with the task's existing details, context, and a user request string.\n\nYour Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the task's details.\nFocus *only* on generating the substance of the update.\n\nOutput Requirements:\n1. Return *only* the newly generated text content as a plain string. Do NOT return a JSON object or any other structured data.\n2. Your string response should NOT include any of the task's original details, unless the user's request explicitly asks to rephrase, summarize, or directly modify existing text.\n3. Do NOT include any timestamps, XML-like tags, markdown, or any other special formatting in your string response.\n4. Ensure the generated text is concise yet complete for the update based on the user request. Avoid conversational fillers or explanations about what you are doing (e.g., do not start with \"Okay, here's the update...\").",
|
"system": "You are an AI assistant helping to append additional information to a software development task. You will be provided with the task's existing details, context, and a user request string.\n\nYour Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the task's details.\nFocus *only* on generating the substance of the update.\n\nOutput Requirements:\n1. Return *only* the newly generated text content as a plain string. Do NOT return a JSON object or any other structured data.\n2. Your string response should NOT include any of the task's original details, unless the user's request explicitly asks to rephrase, summarize, or directly modify existing text.\n3. Do NOT include any timestamps, XML-like tags, markdown, or any other special formatting in your string response.\n4. Ensure the generated text is concise yet complete for the update based on the user request. Avoid conversational fillers or explanations about what you are doing (e.g., do not start with \"Okay, here's the update...\").",
|
||||||
"user": "Task Context:\n\nTask: {{{json task}}}\nCurrent Task Details (for context only):\n{{currentDetails}}\n\nUser Request: \"{{updatePrompt}}\"\n\nBased on the User Request and all the Task Context (including current task details provided above), what is the new information or text that should be appended to this task's details? Return ONLY this new text as a plain string.\n{{#if gatheredContext}}\n\n# Additional Project Context\n\n{{gatheredContext}}\n{{/if}}"
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating the task update:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine relevant files and understand current implementation\n4. Analyze the current codebase to inform your update\n\nBased on your analysis:\n- Include specific file references, code patterns, or implementation details\n- Ensure suggestions align with the project's current architecture\n- Reference existing components or patterns when relevant\n\nProject Root: {{projectRoot}}\n\n{{/if}}Task Context:\n\nTask: {{{json task}}}\nCurrent Task Details (for context only):\n{{currentDetails}}\n\nUser Request: \"{{updatePrompt}}\"\n\nBased on the User Request and all the Task Context (including current task details provided above), what is the new information or text that should be appended to this task's details? Return ONLY this new text as a plain string.\n{{#if gatheredContext}}\n\n# Additional Project Context\n\n{{gatheredContext}}\n{{/if}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,24 @@
|
|||||||
"projectContext": {
|
"projectContext": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Additional project context"
|
"description": "Additional project context"
|
||||||
|
},
|
||||||
|
"hasCodebaseAnalysis": {
|
||||||
|
"type": "boolean",
|
||||||
|
"required": false,
|
||||||
|
"default": false,
|
||||||
|
"description": "Whether codebase analysis is available"
|
||||||
|
},
|
||||||
|
"projectRoot": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false,
|
||||||
|
"default": "",
|
||||||
|
"description": "Project root path for context"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"default": {
|
"default": {
|
||||||
"system": "You are an AI assistant helping to update software development tasks based on new context.\nYou will be given a set of tasks and a prompt describing changes or new implementation details.\nYour job is to update the tasks to reflect these changes, while preserving their basic structure.\n\nCRITICAL RULES:\n1. Return ONLY a JSON array - no explanations, no markdown, no additional text before or after\n2. Each task MUST have ALL fields from the original (do not omit any fields)\n3. Maintain the same IDs, statuses, and dependencies unless specifically mentioned in the prompt\n4. Update titles, descriptions, details, and test strategies to reflect the new information\n5. Do not change anything unnecessarily - just adapt what needs to change based on the prompt\n6. You should return ALL the tasks in order, not just the modified ones\n7. Return a complete valid JSON array with all tasks\n8. VERY IMPORTANT: Preserve all subtasks marked as \"done\" or \"completed\" - do not modify their content\n9. For tasks with completed subtasks, build upon what has already been done rather than rewriting everything\n10. If an existing completed subtask needs to be changed/undone based on the new context, DO NOT modify it directly\n11. Instead, add a new subtask that clearly indicates what needs to be changed or replaced\n12. Use the existence of completed subtasks as an opportunity to make new subtasks more specific and targeted\n\nThe changes described in the prompt should be applied to ALL tasks in the list.",
|
"system": "You are an AI assistant helping to update software development tasks based on new context.\nYou will be given a set of tasks and a prompt describing changes or new implementation details.\nYour job is to update the tasks to reflect these changes, while preserving their basic structure.\n\nCRITICAL RULES:\n1. Return ONLY a JSON array - no explanations, no markdown, no additional text before or after\n2. Each task MUST have ALL fields from the original (do not omit any fields)\n3. Maintain the same IDs, statuses, and dependencies unless specifically mentioned in the prompt\n4. Update titles, descriptions, details, and test strategies to reflect the new information\n5. Do not change anything unnecessarily - just adapt what needs to change based on the prompt\n6. You should return ALL the tasks in order, not just the modified ones\n7. Return a complete valid JSON array with all tasks\n8. VERY IMPORTANT: Preserve all subtasks marked as \"done\" or \"completed\" - do not modify their content\n9. For tasks with completed subtasks, build upon what has already been done rather than rewriting everything\n10. If an existing completed subtask needs to be changed/undone based on the new context, DO NOT modify it directly\n11. Instead, add a new subtask that clearly indicates what needs to be changed or replaced\n12. Use the existence of completed subtasks as an opportunity to make new subtasks more specific and targeted\n\nThe changes described in the prompt should be applied to ALL tasks in the list.",
|
||||||
"user": "Here are the tasks to update:\n{{{json tasks}}}\n\nPlease update these tasks based on the following new context:\n{{updatePrompt}}\n\nIMPORTANT: In the tasks JSON above, any subtasks with \"status\": \"done\" or \"status\": \"completed\" should be preserved exactly as is. Build your changes around these completed items.{{#if projectContext}}\n\n# Project Context\n\n{{projectContext}}{{/if}}\n\nRequired JSON structure for EACH task (ALL fields MUST be present):\n{\n \"id\": <number>,\n \"title\": <string>,\n \"description\": <string>,\n \"status\": <string>,\n \"dependencies\": <array>,\n \"priority\": <string or null>,\n \"details\": <string or null>,\n \"testStrategy\": <string or null>,\n \"subtasks\": <array or null>\n}\n\nReturn a valid JSON array containing ALL the tasks with ALL their fields:\n- id (number) - preserve existing value\n- title (string)\n- description (string)\n- status (string) - preserve existing value unless explicitly changing\n- dependencies (array) - preserve existing value unless explicitly changing\n- priority (string or null)\n- details (string or null)\n- testStrategy (string or null)\n- subtasks (array or null)\n\nReturn ONLY the JSON array now:"
|
"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before updating tasks:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine relevant files and understand current implementation\n4. Analyze how the new changes relate to the existing codebase\n\nBased on your analysis:\n- Update task details to reference specific files, functions, or patterns from the codebase\n- Ensure implementation details align with the project's current architecture\n- Include specific code examples or file references where appropriate\n- Consider how changes impact existing components\n\nProject Root: {{projectRoot}}\n\n{{/if}}Here are the tasks to update:\n{{{json tasks}}}\n\nPlease update these tasks based on the following new context:\n{{updatePrompt}}\n\nIMPORTANT: In the tasks JSON above, any subtasks with \"status\": \"done\" or \"status\": \"completed\" should be preserved exactly as is. Build your changes around these completed items.{{#if projectContext}}\n\n# Project Context\n\n{{projectContext}}{{/if}}\n\nRequired JSON structure for EACH task (ALL fields MUST be present):\n{\n \"id\": <number>,\n \"title\": <string>,\n \"description\": <string>,\n \"status\": <string>,\n \"dependencies\": <array>,\n \"priority\": <string or null>,\n \"details\": <string or null>,\n \"testStrategy\": <string or null>,\n \"subtasks\": <array or null>\n}\n\nReturn a valid JSON array containing ALL the tasks with ALL their fields:\n- id (number) - preserve existing value\n- title (string)\n- description (string)\n- status (string) - preserve existing value unless explicitly changing\n- dependencies (array) - preserve existing value unless explicitly changing\n- priority (string or null)\n- details (string or null)\n- testStrategy (string or null)\n- subtasks (array or null)\n\nReturn ONLY the JSON array now:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,20 +158,25 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await moveTaskModule.moveTasksBetweenTags(
|
const result = await moveTaskModule.moveTasksBetweenTags(
|
||||||
tasksPath,
|
tasksPath,
|
||||||
taskIds,
|
taskIds,
|
||||||
sourceTag,
|
sourceTag,
|
||||||
toTag,
|
toTag,
|
||||||
{
|
{
|
||||||
withDependencies,
|
withDependencies,
|
||||||
ignoreDependencies,
|
ignoreDependencies
|
||||||
force
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(chalk.green('Successfully moved task(s) between tags'));
|
console.log(chalk.green('Successfully moved task(s) between tags'));
|
||||||
|
|
||||||
|
// Print advisory tips when present
|
||||||
|
if (result && Array.isArray(result.tips) && result.tips.length > 0) {
|
||||||
|
console.log('Next Steps:');
|
||||||
|
result.tips.forEach((t) => console.log(` • ${t}`));
|
||||||
|
}
|
||||||
|
|
||||||
// Generate task files for both tags
|
// Generate task files for both tags
|
||||||
await generateTaskFilesModule.default(
|
await generateTaskFilesModule.default(
|
||||||
tasksPath,
|
tasksPath,
|
||||||
@@ -185,6 +190,21 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(chalk.red(`Error: ${error.message}`));
|
console.error(chalk.red(`Error: ${error.message}`));
|
||||||
|
// Print ID collision guidance similar to CLI help block
|
||||||
|
if (
|
||||||
|
typeof error?.message === 'string' &&
|
||||||
|
error.message.includes('already exists in target tag')
|
||||||
|
) {
|
||||||
|
console.log('');
|
||||||
|
console.log('Conflict: ID already exists in target tag');
|
||||||
|
console.log(
|
||||||
|
' • Choose a different target tag without conflicting IDs'
|
||||||
|
);
|
||||||
|
console.log(' • Move a different set of IDs (avoid existing ones)');
|
||||||
|
console.log(
|
||||||
|
' • If needed, move within-tag to a new ID first, then cross-tag move'
|
||||||
|
);
|
||||||
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -268,8 +288,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
'in-progress',
|
'in-progress',
|
||||||
{
|
{
|
||||||
withDependencies: undefined,
|
withDependencies: undefined,
|
||||||
ignoreDependencies: undefined,
|
ignoreDependencies: undefined
|
||||||
force: undefined
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -323,8 +342,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
'in-progress',
|
'in-progress',
|
||||||
{
|
{
|
||||||
withDependencies: true,
|
withDependencies: true,
|
||||||
ignoreDependencies: undefined,
|
ignoreDependencies: undefined
|
||||||
force: undefined
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -350,8 +368,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
'in-progress',
|
'in-progress',
|
||||||
{
|
{
|
||||||
withDependencies: undefined,
|
withDependencies: undefined,
|
||||||
ignoreDependencies: true,
|
ignoreDependencies: true
|
||||||
force: undefined
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -376,8 +393,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
'new-tag',
|
'new-tag',
|
||||||
{
|
{
|
||||||
withDependencies: undefined,
|
withDependencies: undefined,
|
||||||
ignoreDependencies: undefined,
|
ignoreDependencies: undefined
|
||||||
force: undefined
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -440,6 +456,57 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
restore();
|
restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should print advisory tips when result.tips are returned (ignore-dependencies)', async () => {
|
||||||
|
const { errorMessages, logMessages, restore } = captureConsoleAndExit();
|
||||||
|
try {
|
||||||
|
// Arrange: mock move to return tips
|
||||||
|
mockMoveTasksBetweenTags.mockResolvedValue({
|
||||||
|
message: 'ok',
|
||||||
|
tips: [
|
||||||
|
'Run "task-master validate-dependencies" to check for dependency issues.',
|
||||||
|
'Run "task-master fix-dependencies" to automatically repair dangling dependencies.'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
await moveAction({
|
||||||
|
from: '2',
|
||||||
|
fromTag: 'backlog',
|
||||||
|
toTag: 'in-progress',
|
||||||
|
ignoreDependencies: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const joined = logMessages.join('\n');
|
||||||
|
expect(joined).toContain('Next Steps');
|
||||||
|
expect(joined).toContain('validate-dependencies');
|
||||||
|
expect(joined).toContain('fix-dependencies');
|
||||||
|
} finally {
|
||||||
|
restore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should print ID collision suggestions when target already has the ID', async () => {
|
||||||
|
const { errorMessages, logMessages, restore } = captureConsoleAndExit();
|
||||||
|
try {
|
||||||
|
// Arrange: mock move to throw collision
|
||||||
|
const err = new Error(
|
||||||
|
'Task 1 already exists in target tag "in-progress"'
|
||||||
|
);
|
||||||
|
mockMoveTasksBetweenTags.mockRejectedValue(err);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
moveAction({ from: '1', fromTag: 'backlog', toTag: 'in-progress' })
|
||||||
|
).rejects.toThrow('already exists in target tag');
|
||||||
|
|
||||||
|
const joined = logMessages.join('\n');
|
||||||
|
expect(joined).toContain('Conflict: ID already exists in target tag');
|
||||||
|
expect(joined).toContain('different target tag');
|
||||||
|
expect(joined).toContain('different set of IDs');
|
||||||
|
expect(joined).toContain('within-tag');
|
||||||
|
} finally {
|
||||||
|
restore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle same tag error correctly', async () => {
|
it('should handle same tag error correctly', async () => {
|
||||||
const options = {
|
const options = {
|
||||||
from: '1',
|
from: '1',
|
||||||
@@ -485,8 +552,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
from: '1',
|
from: '1',
|
||||||
toTag: 'in-progress',
|
toTag: 'in-progress',
|
||||||
withDependencies: false,
|
withDependencies: false,
|
||||||
ignoreDependencies: false,
|
ignoreDependencies: false
|
||||||
force: false
|
|
||||||
// fromTag is intentionally not provided to test fallback
|
// fromTag is intentionally not provided to test fallback
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -498,8 +564,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
'in-progress',
|
'in-progress',
|
||||||
{
|
{
|
||||||
withDependencies: false,
|
withDependencies: false,
|
||||||
ignoreDependencies: false,
|
ignoreDependencies: false
|
||||||
force: false
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -536,8 +601,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
'in-progress',
|
'in-progress',
|
||||||
{
|
{
|
||||||
withDependencies: undefined,
|
withDependencies: undefined,
|
||||||
ignoreDependencies: undefined,
|
ignoreDependencies: undefined
|
||||||
force: undefined
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -555,32 +619,7 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle --force flag correctly', async () => {
|
// Note: --force flag is no longer supported for cross-tag moves
|
||||||
// Mock successful cross-tag move with force flag
|
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
from: '1',
|
|
||||||
fromTag: 'backlog',
|
|
||||||
toTag: 'in-progress',
|
|
||||||
force: true
|
|
||||||
};
|
|
||||||
|
|
||||||
await moveAction(options);
|
|
||||||
|
|
||||||
expect(mockMoveTasksBetweenTags).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('tasks.json'),
|
|
||||||
[1],
|
|
||||||
'backlog',
|
|
||||||
'in-progress',
|
|
||||||
{
|
|
||||||
withDependencies: undefined,
|
|
||||||
ignoreDependencies: undefined,
|
|
||||||
force: true // Force flag should be passed through
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail when invalid task ID is provided', async () => {
|
it('should fail when invalid task ID is provided', async () => {
|
||||||
const options = {
|
const options = {
|
||||||
@@ -662,90 +701,11 @@ describe('Cross-Tag Move CLI Integration', () => {
|
|||||||
restore();
|
restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should combine --with-dependencies and --force flags correctly', async () => {
|
// Note: --force combinations removed
|
||||||
// Mock successful cross-tag move with both flags
|
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
// Note: --force combinations removed
|
||||||
from: '1,2',
|
|
||||||
fromTag: 'backlog',
|
|
||||||
toTag: 'in-progress',
|
|
||||||
withDependencies: true,
|
|
||||||
force: true
|
|
||||||
};
|
|
||||||
|
|
||||||
await moveAction(options);
|
// Note: --force combinations removed
|
||||||
|
|
||||||
expect(mockMoveTasksBetweenTags).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('tasks.json'),
|
|
||||||
[1, 2],
|
|
||||||
'backlog',
|
|
||||||
'in-progress',
|
|
||||||
{
|
|
||||||
withDependencies: true,
|
|
||||||
ignoreDependencies: undefined,
|
|
||||||
force: true // Both flags should be passed
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should combine --ignore-dependencies and --force flags correctly', async () => {
|
|
||||||
// Mock successful cross-tag move with both flags
|
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
from: '1',
|
|
||||||
fromTag: 'backlog',
|
|
||||||
toTag: 'in-progress',
|
|
||||||
ignoreDependencies: true,
|
|
||||||
force: true
|
|
||||||
};
|
|
||||||
|
|
||||||
await moveAction(options);
|
|
||||||
|
|
||||||
expect(mockMoveTasksBetweenTags).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('tasks.json'),
|
|
||||||
[1],
|
|
||||||
'backlog',
|
|
||||||
'in-progress',
|
|
||||||
{
|
|
||||||
withDependencies: undefined,
|
|
||||||
ignoreDependencies: true,
|
|
||||||
force: true // Both flags should be passed
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle all three flags combined correctly', async () => {
|
|
||||||
// Mock successful cross-tag move with all flags
|
|
||||||
mockMoveTasksBetweenTags.mockResolvedValue(undefined);
|
|
||||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
from: '1,2,3',
|
|
||||||
fromTag: 'backlog',
|
|
||||||
toTag: 'in-progress',
|
|
||||||
withDependencies: true,
|
|
||||||
ignoreDependencies: true,
|
|
||||||
force: true
|
|
||||||
};
|
|
||||||
|
|
||||||
await moveAction(options);
|
|
||||||
|
|
||||||
expect(mockMoveTasksBetweenTags).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('tasks.json'),
|
|
||||||
[1, 2, 3],
|
|
||||||
'backlog',
|
|
||||||
'in-progress',
|
|
||||||
{
|
|
||||||
withDependencies: true,
|
|
||||||
ignoreDependencies: true,
|
|
||||||
force: true // All three flags should be passed
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle whitespace in comma-separated task IDs', async () => {
|
it('should handle whitespace in comma-separated task IDs', async () => {
|
||||||
// Mock successful cross-tag move with whitespace
|
// Mock successful cross-tag move with whitespace
|
||||||
|
|||||||
@@ -426,6 +426,38 @@ describe('Cross-Tag Task Movement Integration Tests', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should provide advisory tips when ignoreDependencies breaks deps', async () => {
|
||||||
|
// Move a task that has dependencies so cross-tag conflicts would be broken
|
||||||
|
const taskIds = [2]; // backlog:2 depends on 1
|
||||||
|
const sourceTag = 'backlog';
|
||||||
|
const targetTag = 'in-progress';
|
||||||
|
|
||||||
|
// Override cross-tag detection to simulate conflicts for this case
|
||||||
|
const depManager = await import(
|
||||||
|
'../../scripts/modules/dependency-manager.js'
|
||||||
|
);
|
||||||
|
depManager.findCrossTagDependencies.mockReturnValueOnce([
|
||||||
|
{ taskId: 2, dependencyId: 1, dependencyTag: sourceTag }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const result = await moveTasksBetweenTags(
|
||||||
|
testDataPath,
|
||||||
|
taskIds,
|
||||||
|
sourceTag,
|
||||||
|
targetTag,
|
||||||
|
{ ignoreDependencies: true },
|
||||||
|
{ projectRoot: '/test/project' }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(Array.isArray(result.tips)).toBe(true);
|
||||||
|
const expectedTips = [
|
||||||
|
'Run "task-master validate-dependencies" to check for dependency issues.',
|
||||||
|
'Run "task-master fix-dependencies" to automatically repair dangling dependencies.'
|
||||||
|
];
|
||||||
|
expect(result.tips).toHaveLength(expectedTips.length);
|
||||||
|
expect(result.tips).toEqual(expect.arrayContaining(expectedTips));
|
||||||
|
});
|
||||||
|
|
||||||
it('should move task without cross-tag dependency conflicts (since dependencies only exist within tags)', async () => {
|
it('should move task without cross-tag dependency conflicts (since dependencies only exist within tags)', async () => {
|
||||||
const taskIds = [2]; // Task 2 depends on Task 1 (both in same tag)
|
const taskIds = [2]; // Task 2 depends on Task 1 (both in same tag)
|
||||||
const sourceTag = 'backlog';
|
const sourceTag = 'backlog';
|
||||||
@@ -564,6 +596,25 @@ describe('Cross-Tag Task Movement Integration Tests', () => {
|
|||||||
{ projectRoot: '/test/project' }
|
{ projectRoot: '/test/project' }
|
||||||
)
|
)
|
||||||
).rejects.toThrow('Task 1 already exists in target tag "in-progress"');
|
).rejects.toThrow('Task 1 already exists in target tag "in-progress"');
|
||||||
|
|
||||||
|
// Validate suggestions on the error payload
|
||||||
|
try {
|
||||||
|
await moveTasksBetweenTags(
|
||||||
|
testDataPath,
|
||||||
|
taskIds,
|
||||||
|
sourceTag,
|
||||||
|
targetTag,
|
||||||
|
{},
|
||||||
|
{ projectRoot: '/test/project' }
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.code).toBe('TASK_ALREADY_EXISTS');
|
||||||
|
expect(Array.isArray(err.data?.suggestions)).toBe(true);
|
||||||
|
const s = (err.data?.suggestions || []).join(' ');
|
||||||
|
expect(s).toContain('different target tag');
|
||||||
|
expect(s).toContain('different set of IDs');
|
||||||
|
expect(s).toContain('within-tag');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -637,37 +688,7 @@ describe('Cross-Tag Task Movement Integration Tests', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle force flag for dependency conflicts', async () => {
|
// Note: force flag deprecated for cross-tag moves; covered by with/ignore dependencies tests
|
||||||
const taskIds = [2]; // Task 2 depends on Task 1
|
|
||||||
const sourceTag = 'backlog';
|
|
||||||
const targetTag = 'in-progress';
|
|
||||||
|
|
||||||
const result = await moveTasksBetweenTags(
|
|
||||||
testDataPath,
|
|
||||||
taskIds,
|
|
||||||
sourceTag,
|
|
||||||
targetTag,
|
|
||||||
{ force: true },
|
|
||||||
{ projectRoot: '/test/project' }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify task was moved despite dependency conflicts
|
|
||||||
expect(mockUtils.writeJSON).toHaveBeenCalledWith(
|
|
||||||
testDataPath,
|
|
||||||
expect.objectContaining({
|
|
||||||
'in-progress': expect.objectContaining({
|
|
||||||
tasks: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: 2,
|
|
||||||
tag: 'in-progress'
|
|
||||||
})
|
|
||||||
])
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
'/test/project',
|
|
||||||
null
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Complex Scenarios', () => {
|
describe('Complex Scenarios', () => {
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ const DEFAULT_CONFIG = {
|
|||||||
projectName: 'Task Master',
|
projectName: 'Task Master',
|
||||||
ollamaBaseURL: 'http://localhost:11434/api',
|
ollamaBaseURL: 'http://localhost:11434/api',
|
||||||
bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com',
|
bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com',
|
||||||
|
enableCodebaseAnalysis: true,
|
||||||
responseLanguage: 'English'
|
responseLanguage: 'English'
|
||||||
},
|
},
|
||||||
claudeCode: {}
|
claudeCode: {}
|
||||||
|
|||||||
135
tests/unit/mcp/tools/move-task-cross-tag-options.test.js
Normal file
135
tests/unit/mcp/tools/move-task-cross-tag-options.test.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import { jest } from '@jest/globals';
|
||||||
|
|
||||||
|
// Mocks
|
||||||
|
const mockFindTasksPath = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue('/test/path/.taskmaster/tasks/tasks.json');
|
||||||
|
jest.unstable_mockModule(
|
||||||
|
'../../../../mcp-server/src/core/utils/path-utils.js',
|
||||||
|
() => ({
|
||||||
|
findTasksPath: mockFindTasksPath
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockEnableSilentMode = jest.fn();
|
||||||
|
const mockDisableSilentMode = jest.fn();
|
||||||
|
jest.unstable_mockModule('../../../../scripts/modules/utils.js', () => ({
|
||||||
|
enableSilentMode: mockEnableSilentMode,
|
||||||
|
disableSilentMode: mockDisableSilentMode
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Spyable mock for moveTasksBetweenTags
|
||||||
|
const mockMoveTasksBetweenTags = jest.fn();
|
||||||
|
jest.unstable_mockModule(
|
||||||
|
'../../../../scripts/modules/task-manager/move-task.js',
|
||||||
|
() => ({
|
||||||
|
moveTasksBetweenTags: mockMoveTasksBetweenTags
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Import after mocks
|
||||||
|
const { moveTaskCrossTagDirect } = await import(
|
||||||
|
'../../../../mcp-server/src/core/direct-functions/move-task-cross-tag.js'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('MCP Cross-Tag Move Direct Function - options & suggestions', () => {
|
||||||
|
const mockLog = { info: jest.fn(), warn: jest.fn(), error: jest.fn() };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes only withDependencies/ignoreDependencies (no force) to core', async () => {
|
||||||
|
// Arrange: make core throw tag validation after call to capture params
|
||||||
|
mockMoveTasksBetweenTags.mockImplementation(() => {
|
||||||
|
const err = new Error('Source tag "invalid" not found or invalid');
|
||||||
|
err.code = 'INVALID_SOURCE_TAG';
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await moveTaskCrossTagDirect(
|
||||||
|
{
|
||||||
|
sourceIds: '1,2',
|
||||||
|
sourceTag: 'backlog',
|
||||||
|
targetTag: 'in-progress',
|
||||||
|
withDependencies: true,
|
||||||
|
projectRoot: '/test'
|
||||||
|
},
|
||||||
|
mockLog
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert options argument (5th param)
|
||||||
|
expect(mockMoveTasksBetweenTags).toHaveBeenCalled();
|
||||||
|
const args = mockMoveTasksBetweenTags.mock.calls[0];
|
||||||
|
const moveOptions = args[4];
|
||||||
|
expect(moveOptions).toEqual({
|
||||||
|
withDependencies: true,
|
||||||
|
ignoreDependencies: false
|
||||||
|
});
|
||||||
|
expect('force' in moveOptions).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns conflict suggestions on cross-tag dependency conflicts', async () => {
|
||||||
|
// Arrange: core throws cross-tag dependency conflicts
|
||||||
|
mockMoveTasksBetweenTags.mockImplementation(() => {
|
||||||
|
const err = new Error(
|
||||||
|
'Cannot move tasks: 2 cross-tag dependency conflicts found'
|
||||||
|
);
|
||||||
|
err.code = 'CROSS_TAG_DEPENDENCY_CONFLICTS';
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await moveTaskCrossTagDirect(
|
||||||
|
{
|
||||||
|
sourceIds: '1',
|
||||||
|
sourceTag: 'backlog',
|
||||||
|
targetTag: 'in-progress',
|
||||||
|
projectRoot: '/test'
|
||||||
|
},
|
||||||
|
mockLog
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
expect(result.error.code).toBe('CROSS_TAG_DEPENDENCY_CONFLICT');
|
||||||
|
expect(Array.isArray(result.error.suggestions)).toBe(true);
|
||||||
|
// Key suggestions
|
||||||
|
const s = result.error.suggestions.join(' ');
|
||||||
|
expect(s).toContain('--with-dependencies');
|
||||||
|
expect(s).toContain('--ignore-dependencies');
|
||||||
|
expect(s).toContain('validate-dependencies');
|
||||||
|
expect(s).toContain('Move dependencies first');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns ID collision suggestions when target tag already has the ID', async () => {
|
||||||
|
// Arrange: core throws TASK_ALREADY_EXISTS structured error
|
||||||
|
mockMoveTasksBetweenTags.mockImplementation(() => {
|
||||||
|
const err = new Error(
|
||||||
|
'Task 1 already exists in target tag "in-progress"'
|
||||||
|
);
|
||||||
|
err.code = 'TASK_ALREADY_EXISTS';
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await moveTaskCrossTagDirect(
|
||||||
|
{
|
||||||
|
sourceIds: '1',
|
||||||
|
sourceTag: 'backlog',
|
||||||
|
targetTag: 'in-progress',
|
||||||
|
projectRoot: '/test'
|
||||||
|
},
|
||||||
|
mockLog
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
expect(result.error.code).toBe('TASK_ALREADY_EXISTS');
|
||||||
|
const joined = (result.error.suggestions || []).join(' ');
|
||||||
|
expect(joined).toContain('different target tag');
|
||||||
|
expect(joined).toContain('different set of IDs');
|
||||||
|
expect(joined).toContain('within-tag');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -52,7 +52,8 @@ jest.unstable_mockModule('../../scripts/modules/config-manager.js', () => ({
|
|||||||
VALID_PROVIDERS: ['anthropic', 'perplexity'],
|
VALID_PROVIDERS: ['anthropic', 'perplexity'],
|
||||||
validateProvider: jest.fn(() => true),
|
validateProvider: jest.fn(() => true),
|
||||||
validateProviderModelCombination: jest.fn(() => true),
|
validateProviderModelCombination: jest.fn(() => true),
|
||||||
isApiKeySet: jest.fn(() => true)
|
isApiKeySet: jest.fn(() => true),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Mock utils comprehensively to prevent CLI behavior
|
// Mock utils comprehensively to prevent CLI behavior
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Tests for the add-task.js module
|
* Tests for the add-task.js module
|
||||||
*/
|
*/
|
||||||
import { jest } from '@jest/globals';
|
import { jest } from '@jest/globals';
|
||||||
|
import { hasCodebaseAnalysis } from '../../../../../scripts/modules/config-manager.js';
|
||||||
|
|
||||||
// Mock the dependencies before importing the module under test
|
// Mock the dependencies before importing the module under test
|
||||||
jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
|
jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
|
||||||
@@ -99,7 +100,8 @@ jest.unstable_mockModule(
|
|||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/config-manager.js',
|
'../../../../../scripts/modules/config-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
getDefaultPriority: jest.fn(() => 'medium')
|
getDefaultPriority: jest.fn(() => 'medium'),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -187,7 +187,8 @@ jest.unstable_mockModule(
|
|||||||
// Additional functions
|
// Additional functions
|
||||||
getAllProviders: jest.fn(() => ['anthropic', 'openai', 'perplexity']),
|
getAllProviders: jest.fn(() => ['anthropic', 'openai', 'perplexity']),
|
||||||
getVertexProjectId: jest.fn(() => undefined),
|
getVertexProjectId: jest.fn(() => undefined),
|
||||||
getVertexLocation: jest.fn(() => undefined)
|
getVertexLocation: jest.fn(() => undefined),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -301,7 +301,8 @@ jest.unstable_mockModule(
|
|||||||
// Additional functions
|
// Additional functions
|
||||||
getAllProviders: jest.fn(() => ['anthropic', 'openai', 'perplexity']),
|
getAllProviders: jest.fn(() => ['anthropic', 'openai', 'perplexity']),
|
||||||
getVertexProjectId: jest.fn(() => undefined),
|
getVertexProjectId: jest.fn(() => undefined),
|
||||||
getVertexLocation: jest.fn(() => undefined)
|
getVertexLocation: jest.fn(() => undefined),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ jest.unstable_mockModule(
|
|||||||
getDebugFlag: jest.fn(() => false),
|
getDebugFlag: jest.fn(() => false),
|
||||||
getDefaultNumTasks: jest.fn(() => 10),
|
getDefaultNumTasks: jest.fn(() => 10),
|
||||||
getMainProvider: jest.fn(() => 'openai'),
|
getMainProvider: jest.fn(() => 'openai'),
|
||||||
getResearchProvider: jest.fn(() => 'perplexity')
|
getResearchProvider: jest.fn(() => 'perplexity'),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -219,6 +219,37 @@ describe('Cross-Tag Task Movement', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// New test: ensure with-dependencies only traverses tasks from the source tag
|
||||||
|
it('should scope dependency traversal to source tag when using --with-dependencies', async () => {
|
||||||
|
findCrossTagDependencies.mockReturnValue([]);
|
||||||
|
validateSubtaskMove.mockImplementation(() => {});
|
||||||
|
|
||||||
|
const result = await moveTasksBetweenTags(
|
||||||
|
mockTasksPath,
|
||||||
|
[1], // backlog:1 depends on backlog:2
|
||||||
|
'backlog',
|
||||||
|
'in-progress',
|
||||||
|
{ withDependencies: true },
|
||||||
|
mockContext
|
||||||
|
);
|
||||||
|
|
||||||
|
// Write should include backlog:2 moved, and must NOT traverse or fetch dependencies from the target tag
|
||||||
|
expect(writeJSON).toHaveBeenCalledWith(
|
||||||
|
mockTasksPath,
|
||||||
|
expect.objectContaining({
|
||||||
|
'in-progress': expect.objectContaining({
|
||||||
|
tasks: expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: 1 }),
|
||||||
|
expect.objectContaining({ id: 2 }) // the backlog:2 now moved
|
||||||
|
// ensure existing in-progress:2 remains (by id) but we don't double-add or fetch deps from it
|
||||||
|
])
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
mockContext.projectRoot,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe('moveTasksBetweenTags', () => {
|
describe('moveTasksBetweenTags', () => {
|
||||||
it('should move tasks without dependencies successfully', async () => {
|
it('should move tasks without dependencies successfully', async () => {
|
||||||
// Mock the dependency functions to return no conflicts
|
// Mock the dependency functions to return no conflicts
|
||||||
|
|||||||
@@ -187,7 +187,8 @@ jest.unstable_mockModule(
|
|||||||
getDefaultNumTasks: jest.fn(() => 10),
|
getDefaultNumTasks: jest.fn(() => 10),
|
||||||
getDefaultPriority: jest.fn(() => 'medium'),
|
getDefaultPriority: jest.fn(() => 'medium'),
|
||||||
getMainProvider: jest.fn(() => 'openai'),
|
getMainProvider: jest.fn(() => 'openai'),
|
||||||
getResearchProvider: jest.fn(() => 'perplexity')
|
getResearchProvider: jest.fn(() => 'perplexity'),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ jest.unstable_mockModule(
|
|||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/config-manager.js',
|
'../../../../../scripts/modules/config-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
getDebugFlag: jest.fn(() => false)
|
getDebugFlag: jest.fn(() => false),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ jest.unstable_mockModule(
|
|||||||
'../../../../../scripts/modules/config-manager.js',
|
'../../../../../scripts/modules/config-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
getDebugFlag: jest.fn(() => false),
|
getDebugFlag: jest.fn(() => false),
|
||||||
isApiKeySet: jest.fn(() => true)
|
isApiKeySet: jest.fn(() => true),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
|
|||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/config-manager.js',
|
'../../../../../scripts/modules/config-manager.js',
|
||||||
() => ({
|
() => ({
|
||||||
getDebugFlag: jest.fn(() => false)
|
getDebugFlag: jest.fn(() => false),
|
||||||
|
hasCodebaseAnalysis: jest.fn(() => false)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user