Compare commits
4 Commits
task-maste
...
fix/merge.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99fc67a09f | ||
|
|
b1fd0ec0c9 | ||
|
|
f662654afb | ||
|
|
a8e2d728c9 |
12
.changeset/claude-import-fix-new.md
Normal file
12
.changeset/claude-import-fix-new.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
"task-master-ai": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Prevent CLAUDE.md overwrite by using Claude Code's import feature
|
||||||
|
|
||||||
|
- Task Master now creates its instructions in `.taskmaster/CLAUDE.md` instead of overwriting the user's `CLAUDE.md`
|
||||||
|
- Adds an import section to the user's CLAUDE.md that references the Task Master instructions
|
||||||
|
- Preserves existing user content in CLAUDE.md files
|
||||||
|
- Provides clean uninstall that only removes Task Master's additions
|
||||||
|
|
||||||
|
**Breaking Change**: Task Master instructions for Claude Code are now stored in `.taskmaster/CLAUDE.md` and imported into the main CLAUDE.md file. Users who previously had Task Master content directly in their CLAUDE.md will need to run `task-master rules remove claude` followed by `task-master rules add claude` to migrate to the new structure.
|
||||||
7
.changeset/ten-glasses-feel.md
Normal file
7
.changeset/ten-glasses-feel.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"task-master-ai": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fixed the comprehensive taskmaster system integration via custom slash commands with proper syntax
|
||||||
|
|
||||||
|
- Provide claude clode with a complete set of of commands that can trigger task master events directly within Claude Code
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
reviews:
|
|
||||||
profile: assertive
|
|
||||||
poem: false
|
|
||||||
auto_review:
|
|
||||||
base_branches:
|
|
||||||
- rc
|
|
||||||
- beta
|
|
||||||
- alpha
|
|
||||||
- production
|
|
||||||
- next
|
|
||||||
@@ -8,7 +8,6 @@ GROQ_API_KEY=YOUR_GROQ_KEY_HERE
|
|||||||
OPENROUTER_API_KEY=YOUR_OPENROUTER_KEY_HERE
|
OPENROUTER_API_KEY=YOUR_OPENROUTER_KEY_HERE
|
||||||
XAI_API_KEY=YOUR_XAI_KEY_HERE
|
XAI_API_KEY=YOUR_XAI_KEY_HERE
|
||||||
AZURE_OPENAI_API_KEY=YOUR_AZURE_KEY_HERE
|
AZURE_OPENAI_API_KEY=YOUR_AZURE_KEY_HERE
|
||||||
OLLAMA_API_KEY=YOUR_OLLAMA_API_KEY_HERE
|
|
||||||
|
|
||||||
# Google Vertex AI Configuration
|
# Google Vertex AI Configuration
|
||||||
VERTEX_PROJECT_ID=your-gcp-project-id
|
VERTEX_PROJECT_ID=your-gcp-project-id
|
||||||
|
|||||||
134
CHANGELOG.md
134
CHANGELOG.md
@@ -1,139 +1,5 @@
|
|||||||
# task-master-ai
|
# task-master-ai
|
||||||
|
|
||||||
## 0.21.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`9c58a92`](https://github.com/eyaltoledano/claude-task-master/commit/9c58a922436c0c5e7ff1b20ed2edbc269990c772) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Kiro editor rule profile support
|
|
||||||
- Add support for Kiro IDE with custom rule files and MCP configuration
|
|
||||||
- Generate rule files in `.kiro/steering/` directory with markdown format
|
|
||||||
- Include MCP server configuration with enhanced file inclusion patterns
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Created a comprehensive documentation site for Task Master AI. Visit https://docs.task-master.dev to explore guides, API references, and examples.
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`58a301c`](https://github.com/eyaltoledano/claude-task-master/commit/58a301c380d18a9d9509137f3e989d24200a5faa) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Complete Groq provider integration and add MoonshotAI Kimi K2 model support
|
|
||||||
- Fixed Groq provider registration
|
|
||||||
- Added Groq API key validation
|
|
||||||
- Added GROQ_API_KEY to .env.example
|
|
||||||
- Added moonshotai/kimi-k2-instruct model with $1/$3 per 1M token pricing and 16k max output
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`b0e09c7`](https://github.com/eyaltoledano/claude-task-master/commit/b0e09c76ed73b00434ac95606679f570f1015a3d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - feat: Add Zed editor rule profile with agent rules and MCP config
|
|
||||||
- Resolves #637
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`6c5e0f9`](https://github.com/eyaltoledano/claude-task-master/commit/6c5e0f97f8403c4da85c1abba31cb8b1789511a7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Amp rule profile with AGENT.md and MCP config
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve project root detection
|
|
||||||
- No longer creates an infinite loop when unable to detect your code workspace
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`36c4a7a`](https://github.com/eyaltoledano/claude-task-master/commit/36c4a7a86924c927ad7f86a4f891f66ad55eb4d2) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add OpenCode profile with AGENTS.md and MCP config
|
|
||||||
- Resolves #965
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Make `task-master update` more reliable with AI responses
|
|
||||||
|
|
||||||
The `update` command now handles AI responses more robustly. If the AI forgets to include certain task fields, the command will automatically fill in the missing data from your original tasks instead of failing. This means smoother bulk task updates without losing important information like IDs, dependencies, or completed subtasks.
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtask dependency validation when expanding tasks
|
|
||||||
|
|
||||||
When using `task-master expand` to break down tasks into subtasks, dependencies between subtasks are now properly validated. Previously, subtasks with dependencies would fail validation. Now subtasks can correctly depend on their siblings within the same parent task.
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`6d69d02`](https://github.com/eyaltoledano/claude-task-master/commit/6d69d02fe03edcc785380415995d5cfcdd97acbb) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Prevent CLAUDE.md overwrite by using Claude Code's import feature
|
|
||||||
- Task Master now creates its instructions in `.taskmaster/CLAUDE.md` instead of overwriting the user's `CLAUDE.md`
|
|
||||||
- Adds an import section to the user's CLAUDE.md that references the Task Master instructions
|
|
||||||
- Preserves existing user content in CLAUDE.md files
|
|
||||||
- Provides clean uninstall that only removes Task Master's additions
|
|
||||||
|
|
||||||
**Breaking Change**: Task Master instructions for Claude Code are now stored in `.taskmaster/CLAUDE.md` and imported into the main CLAUDE.md file. Users who previously had Task Master content directly in their CLAUDE.md will need to run `task-master rules remove claude` followed by `task-master rules add claude` to migrate to the new structure.
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`fd005c4`](https://github.com/eyaltoledano/claude-task-master/commit/fd005c4c5481ffac58b11f01a448fa5b29056b8d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Implement Boundary-First Tag Resolution to ensure consistent and deterministic tag handling across CLI and MCP, resolving potential race conditions.
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix `task-master lang --setup` breaking when no language is defined, now defaults to English
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`624922c`](https://github.com/eyaltoledano/claude-task-master/commit/624922ca598c4ce8afe9a5646ebb375d4616db63) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix: show command no longer requires complexity report file to exist
|
|
||||||
|
|
||||||
The `tm show` command was incorrectly requiring the complexity report file to exist even when not needed. Now it only validates the complexity report path when a custom report file is explicitly provided via the -r/--report option.
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`858d4a1`](https://github.com/eyaltoledano/claude-task-master/commit/858d4a1c5486d20e7e3a8e37e3329d7fb8200310) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Update VS Code profile with MCP config transformation
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`0451ebc`](https://github.com/eyaltoledano/claude-task-master/commit/0451ebcc32cd7e9d395b015aaa8602c4734157e1) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when retrieving tools and resources
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`0a70ab6`](https://github.com/eyaltoledano/claude-task-master/commit/0a70ab6179cb2b5b4b2d9dc256a7a3b69a0e5dd6) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add MCP configuration support to Claude Code rules
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`4629128`](https://github.com/eyaltoledano/claude-task-master/commit/4629128943f6283385f4762c09cf2752f855cc33) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed the comprehensive taskmaster system integration via custom slash commands with proper syntax
|
|
||||||
- Provide claude clode with a complete set of of commands that can trigger task master events directly within Claude Code
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`0886c83`](https://github.com/eyaltoledano/claude-task-master/commit/0886c83d0c678417c0313256a6dd96f7ee2c9ac6) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Correct MCP server name and use 'Add to Cursor' button with updated placeholder keys.
|
|
||||||
|
|
||||||
- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`88c434a`](https://github.com/eyaltoledano/claude-task-master/commit/88c434a9393e429d9277f59b3e20f1005076bbe0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add missing API keys to .env.example and README.md
|
|
||||||
|
|
||||||
## 0.21.0-rc.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#1001](https://github.com/eyaltoledano/claude-task-master/pull/1001) [`75a36ea`](https://github.com/eyaltoledano/claude-task-master/commit/75a36ea99a1c738a555bdd4fe7c763d0c5925e37) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Kiro editor rule profile support
|
|
||||||
- Add support for Kiro IDE with custom rule files and MCP configuration
|
|
||||||
- Generate rule files in `.kiro/steering/` directory with markdown format
|
|
||||||
- Include MCP server configuration with enhanced file inclusion patterns
|
|
||||||
|
|
||||||
- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Created a comprehensive documentation site for Task Master AI. Visit https://docs.task-master.dev to explore guides, API references, and examples.
|
|
||||||
|
|
||||||
- [#978](https://github.com/eyaltoledano/claude-task-master/pull/978) [`fedfd6a`](https://github.com/eyaltoledano/claude-task-master/commit/fedfd6a0f41a78094f7ee7f69be689b699475a79) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Complete Groq provider integration and add MoonshotAI Kimi K2 model support
|
|
||||||
- Fixed Groq provider registration
|
|
||||||
- Added Groq API key validation
|
|
||||||
- Added GROQ_API_KEY to .env.example
|
|
||||||
- Added moonshotai/kimi-k2-instruct model with $1/$3 per 1M token pricing and 16k max output
|
|
||||||
|
|
||||||
- [#974](https://github.com/eyaltoledano/claude-task-master/pull/974) [`5b0eda0`](https://github.com/eyaltoledano/claude-task-master/commit/5b0eda07f20a365aa2ec1736eed102bca81763a9) Thanks [@joedanz](https://github.com/joedanz)! - feat: Add Zed editor rule profile with agent rules and MCP config
|
|
||||||
- Resolves #637
|
|
||||||
|
|
||||||
- [#973](https://github.com/eyaltoledano/claude-task-master/pull/973) [`6d05e86`](https://github.com/eyaltoledano/claude-task-master/commit/6d05e8622c1d761acef10414940ff9a766b3b57d) Thanks [@joedanz](https://github.com/joedanz)! - Add Amp rule profile with AGENT.md and MCP config
|
|
||||||
|
|
||||||
- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve project root detection
|
|
||||||
- No longer creates an infinite loop when unable to detect your code workspace
|
|
||||||
|
|
||||||
- [#970](https://github.com/eyaltoledano/claude-task-master/pull/970) [`b87499b`](https://github.com/eyaltoledano/claude-task-master/commit/b87499b56e626001371a87ed56ffc72675d829f3) Thanks [@joedanz](https://github.com/joedanz)! - Add OpenCode profile with AGENTS.md and MCP config
|
|
||||||
- Resolves #965
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Make `task-master update` more reliable with AI responses
|
|
||||||
|
|
||||||
The `update` command now handles AI responses more robustly. If the AI forgets to include certain task fields, the command will automatically fill in the missing data from your original tasks instead of failing. This means smoother bulk task updates without losing important information like IDs, dependencies, or completed subtasks.
|
|
||||||
|
|
||||||
- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtask dependency validation when expanding tasks
|
|
||||||
|
|
||||||
When using `task-master expand` to break down tasks into subtasks, dependencies between subtasks are now properly validated. Previously, subtasks with dependencies would fail validation. Now subtasks can correctly depend on their siblings within the same parent task.
|
|
||||||
|
|
||||||
- [#949](https://github.com/eyaltoledano/claude-task-master/pull/949) [`f662654`](https://github.com/eyaltoledano/claude-task-master/commit/f662654afb8e7a230448655265d6f41adf6df62c) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Prevent CLAUDE.md overwrite by using Claude Code's import feature
|
|
||||||
- Task Master now creates its instructions in `.taskmaster/CLAUDE.md` instead of overwriting the user's `CLAUDE.md`
|
|
||||||
- Adds an import section to the user's CLAUDE.md that references the Task Master instructions
|
|
||||||
- Preserves existing user content in CLAUDE.md files
|
|
||||||
- Provides clean uninstall that only removes Task Master's additions
|
|
||||||
|
|
||||||
**Breaking Change**: Task Master instructions for Claude Code are now stored in `.taskmaster/CLAUDE.md` and imported into the main CLAUDE.md file. Users who previously had Task Master content directly in their CLAUDE.md will need to run `task-master rules remove claude` followed by `task-master rules add claude` to migrate to the new structure.
|
|
||||||
|
|
||||||
- [#943](https://github.com/eyaltoledano/claude-task-master/pull/943) [`f98df5c`](https://github.com/eyaltoledano/claude-task-master/commit/f98df5c0fdb253b2b55d4278c11d626529c4dba4) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Implement Boundary-First Tag Resolution to ensure consistent and deterministic tag handling across CLI and MCP, resolving potential race conditions.
|
|
||||||
|
|
||||||
- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix `task-master lang --setup` breaking when no language is defined, now defaults to English
|
|
||||||
|
|
||||||
- [#979](https://github.com/eyaltoledano/claude-task-master/pull/979) [`ab2e946`](https://github.com/eyaltoledano/claude-task-master/commit/ab2e94608749a2f148118daa0443bd32bca6e7a1) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Fix: show command no longer requires complexity report file to exist
|
|
||||||
|
|
||||||
The `tm show` command was incorrectly requiring the complexity report file to exist even when not needed. Now it only validates the complexity report path when a custom report file is explicitly provided via the -r/--report option.
|
|
||||||
|
|
||||||
- [#971](https://github.com/eyaltoledano/claude-task-master/pull/971) [`5544222`](https://github.com/eyaltoledano/claude-task-master/commit/55442226d0aa4870470d2a9897f5538d6a0e329e) Thanks [@joedanz](https://github.com/joedanz)! - Update VS Code profile with MCP config transformation
|
|
||||||
|
|
||||||
- [#1002](https://github.com/eyaltoledano/claude-task-master/pull/1002) [`6d0654c`](https://github.com/eyaltoledano/claude-task-master/commit/6d0654cb4191cee794e1c8cbf2b92dc33d4fb410) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when retrieving tools and resources
|
|
||||||
|
|
||||||
- [#980](https://github.com/eyaltoledano/claude-task-master/pull/980) [`cc4fe20`](https://github.com/eyaltoledano/claude-task-master/commit/cc4fe205fb468e7144c650acc92486df30731560) Thanks [@joedanz](https://github.com/joedanz)! - Add MCP configuration support to Claude Code rules
|
|
||||||
|
|
||||||
- [#968](https://github.com/eyaltoledano/claude-task-master/pull/968) [`7b4803a`](https://github.com/eyaltoledano/claude-task-master/commit/7b4803a479105691c7ed032fd878fe3d48d82724) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed the comprehensive taskmaster system integration via custom slash commands with proper syntax
|
|
||||||
- Provide claude clode with a complete set of of commands that can trigger task master events directly within Claude Code
|
|
||||||
|
|
||||||
- [#995](https://github.com/eyaltoledano/claude-task-master/pull/995) [`b78de8d`](https://github.com/eyaltoledano/claude-task-master/commit/b78de8dbb4d6dc93b48e2f81c32960ef069736ed) Thanks [@joedanz](https://github.com/joedanz)! - Correct MCP server name and use 'Add to Cursor' button with updated placeholder keys.
|
|
||||||
|
|
||||||
- [#972](https://github.com/eyaltoledano/claude-task-master/pull/972) [`1c7badf`](https://github.com/eyaltoledano/claude-task-master/commit/1c7badff2f5c548bfa90a3b2634e63087a382a84) Thanks [@joedanz](https://github.com/joedanz)! - Add missing API keys to .env.example and README.md
|
|
||||||
|
|
||||||
## 0.20.0
|
## 0.20.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -14,13 +14,7 @@ A task management system for AI-driven development with Claude, designed to work
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
📚 **[View Full Documentation](https://docs.task-master.dev)**
|
For more detailed information, check out the documentation in the `docs` directory:
|
||||||
|
|
||||||
For detailed guides, API references, and comprehensive examples, visit our documentation site.
|
|
||||||
|
|
||||||
### Quick Reference
|
|
||||||
|
|
||||||
The following documentation is also available in the `docs` directory:
|
|
||||||
|
|
||||||
- [Configuration Guide](docs/configuration.md) - Set up environment variables and customize Task Master
|
- [Configuration Guide](docs/configuration.md) - Set up environment variables and customize Task Master
|
||||||
- [Tutorial](docs/tutorial.md) - Step-by-step guide to getting started with Task Master
|
- [Tutorial](docs/tutorial.md) - Step-by-step guide to getting started with Task Master
|
||||||
@@ -31,7 +25,11 @@ The following documentation is also available in the `docs` directory:
|
|||||||
|
|
||||||
#### Quick Install for Cursor 1.0+ (One-Click)
|
#### Quick Install for Cursor 1.0+ (One-Click)
|
||||||
|
|
||||||
[](https://cursor.com/install-mcp?name=task-master-ai&config=eyJjb21tYW5kIjoibnB4IC15IC0tcGFja2FnZT10YXNrLW1hc3Rlci1haSB0YXNrLW1hc3Rlci1haSIsImVudiI6eyJBTlRIUk9QSUNfQVBJX0tFWSI6IllPVVJfQU5USFJPUElDX0FQSV9LRVlfSEVSRSIsIlBFUlBMRVhJVFlfQVBJX0tFWSI6IllPVVJfUEVSUExFWElUWV9BUElfS0VZX0hFUkUiLCJPUEVOQUlfQVBJX0tFWSI6IllPVVJfT1BFTkFJX0tFWV9IRVJFIiwiR09PR0xFX0FQSV9LRVkiOiJZT1VSX0dPT0dMRV9LRVlfSEVSRSIsIk1JU1RSQUxfQVBJX0tFWSI6IllPVVJfTUlTVFJBTF9LRVlfSEVSRSIsIkdST1FfQVBJX0tFWSI6IllPVVJfR1JPUV9LRVlfSEVSRSIsIk9QRU5ST1VURVJfQVBJX0tFWSI6IllPVVJfT1BFTlJPVVRFUl9LRVlfSEVSRSIsIlhBSV9BUElfS0VZIjoiWU9VUl9YQUlfS0VZX0hFUkUiLCJBWlVSRV9PUEVOQUlfQVBJX0tFWSI6IllPVVJfQVpVUkVfS0VZX0hFUkUiLCJPTExBTUFfQVBJX0tFWSI6IllPVVJfT0xMQU1BX0FQSV9LRVlfSEVSRSJ9fQ%3D%3D)
|
📋 Click the copy button (top-right of code block) then paste into your browser:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cursor://anysphere.cursor-deeplink/mcp/install?name=taskmaster-ai&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIi0tcGFja2FnZT10YXNrLW1hc3Rlci1haSIsInRhc2stbWFzdGVyLWFpIl0sImVudiI6eyJBTlRIUk9QSUNfQVBJX0tFWSI6IllPVVJfQU5USFJPUElDX0FQSV9LRVlfSEVSRSIsIlBFUlBMRVhJVFlfQVBJX0tFWSI6IllPVVJfUEVSUExFWElUWV9BUElfS0VZX0hFUkUiLCJPUEVOQUlfQVBJX0tFWSI6IllPVVJfT1BFTkFJX0tFWV9IRVJFIiwiR09PR0xFX0FQSV9LRVkiOiJZT1VSX0dPT0dMRV9LRVlfSEVSRSIsIk1JU1RSQUxfQVBJX0tFWSI6IllPVVJfTUlTVFJBTF9LRVlfSEVSRSIsIk9QRU5ST1VURVJfQVBJX0tFWSI6IllPVVJfT1BFTlJPVVRFUl9LRVlfSEVSRSIsIlhBSV9BUElfS0VZIjoiWU9VUl9YQUlfS0VZX0hFUkUiLCJBWlVSRV9PUEVOQUlfQVBJX0tFWSI6IllPVVJfQVpVUkVfS0VZX0hFUkUiLCJPTExBTUFfQVBJX0tFWSI6IllPVVJfT0xMQU1BX0FQSV9LRVlfSEVSRSJ9fQo=
|
||||||
|
```
|
||||||
|
|
||||||
> **Note:** After clicking the link, you'll still need to add your API keys to the configuration. The link installs the MCP server with placeholder keys that you'll need to replace with your actual API keys.
|
> **Note:** After clicking the link, you'll still need to add your API keys to the configuration. The link installs the MCP server with placeholder keys that you'll need to replace with your actual API keys.
|
||||||
|
|
||||||
@@ -75,7 +73,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"task-master-ai": {
|
"taskmaster-ai": {
|
||||||
"command": "npx",
|
"command": "npx",
|
||||||
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
|
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
|
||||||
"env": {
|
"env": {
|
||||||
@@ -84,7 +82,6 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
|
|||||||
"OPENAI_API_KEY": "YOUR_OPENAI_KEY_HERE",
|
"OPENAI_API_KEY": "YOUR_OPENAI_KEY_HERE",
|
||||||
"GOOGLE_API_KEY": "YOUR_GOOGLE_KEY_HERE",
|
"GOOGLE_API_KEY": "YOUR_GOOGLE_KEY_HERE",
|
||||||
"MISTRAL_API_KEY": "YOUR_MISTRAL_KEY_HERE",
|
"MISTRAL_API_KEY": "YOUR_MISTRAL_KEY_HERE",
|
||||||
"GROQ_API_KEY": "YOUR_GROQ_KEY_HERE",
|
|
||||||
"OPENROUTER_API_KEY": "YOUR_OPENROUTER_KEY_HERE",
|
"OPENROUTER_API_KEY": "YOUR_OPENROUTER_KEY_HERE",
|
||||||
"XAI_API_KEY": "YOUR_XAI_KEY_HERE",
|
"XAI_API_KEY": "YOUR_XAI_KEY_HERE",
|
||||||
"AZURE_OPENAI_API_KEY": "YOUR_AZURE_KEY_HERE",
|
"AZURE_OPENAI_API_KEY": "YOUR_AZURE_KEY_HERE",
|
||||||
@@ -104,7 +101,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"servers": {
|
"servers": {
|
||||||
"task-master-ai": {
|
"taskmaster-ai": {
|
||||||
"command": "npx",
|
"command": "npx",
|
||||||
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
|
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
|
||||||
"env": {
|
"env": {
|
||||||
@@ -113,11 +110,9 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
|
|||||||
"OPENAI_API_KEY": "YOUR_OPENAI_KEY_HERE",
|
"OPENAI_API_KEY": "YOUR_OPENAI_KEY_HERE",
|
||||||
"GOOGLE_API_KEY": "YOUR_GOOGLE_KEY_HERE",
|
"GOOGLE_API_KEY": "YOUR_GOOGLE_KEY_HERE",
|
||||||
"MISTRAL_API_KEY": "YOUR_MISTRAL_KEY_HERE",
|
"MISTRAL_API_KEY": "YOUR_MISTRAL_KEY_HERE",
|
||||||
"GROQ_API_KEY": "YOUR_GROQ_KEY_HERE",
|
|
||||||
"OPENROUTER_API_KEY": "YOUR_OPENROUTER_KEY_HERE",
|
"OPENROUTER_API_KEY": "YOUR_OPENROUTER_KEY_HERE",
|
||||||
"XAI_API_KEY": "YOUR_XAI_KEY_HERE",
|
"XAI_API_KEY": "YOUR_XAI_KEY_HERE",
|
||||||
"AZURE_OPENAI_API_KEY": "YOUR_AZURE_KEY_HERE",
|
"AZURE_OPENAI_API_KEY": "YOUR_AZURE_KEY_HERE"
|
||||||
"OLLAMA_API_KEY": "YOUR_OLLAMA_API_KEY_HERE"
|
|
||||||
},
|
},
|
||||||
"type": "stdio"
|
"type": "stdio"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "extension",
|
|
||||||
"private": true,
|
|
||||||
"version": "0.20.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"description": "",
|
|
||||||
"devDependencies": {
|
|
||||||
"typescript": "^5.8.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
console.log('hello world');
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
|
||||||
|
|
||||||
/* Projects */
|
|
||||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
|
||||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
|
||||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
|
||||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
|
||||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
|
||||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
||||||
|
|
||||||
/* Language and Environment */
|
|
||||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
|
||||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
||||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
||||||
// "libReplacement": true, /* Enable lib replacement. */
|
|
||||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
|
||||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
|
||||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
|
||||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
|
||||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
|
||||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
|
||||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
|
||||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
|
||||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
|
||||||
|
|
||||||
/* Modules */
|
|
||||||
"module": "commonjs" /* Specify what module code is generated. */,
|
|
||||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
|
||||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
|
||||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
|
||||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
|
||||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
|
||||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
|
||||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
||||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
|
||||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
|
||||||
// "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
|
|
||||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
|
||||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
|
||||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
|
||||||
// "noUncheckedSideEffectImports": true, /* Check side effect imports. */
|
|
||||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
|
||||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
|
||||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
|
||||||
|
|
||||||
/* JavaScript Support */
|
|
||||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
|
||||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
|
||||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
|
||||||
|
|
||||||
/* Emit */
|
|
||||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
|
||||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
|
||||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
|
||||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
|
||||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
|
||||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
|
||||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
|
||||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
|
||||||
// "removeComments": true, /* Disable emitting comments. */
|
|
||||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
|
||||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
|
||||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
|
||||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
||||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
|
||||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
|
||||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
|
||||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
|
||||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
|
||||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
|
||||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
|
||||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
|
||||||
|
|
||||||
/* Interop Constraints */
|
|
||||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
|
||||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
|
||||||
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
|
|
||||||
// "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */
|
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
|
||||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
|
||||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
|
||||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
|
||||||
|
|
||||||
/* Type Checking */
|
|
||||||
"strict": true /* Enable all strict type-checking options. */,
|
|
||||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
|
||||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
|
||||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
|
||||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
|
||||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
|
||||||
// "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
|
|
||||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
|
||||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
|
||||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
|
||||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
|
||||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
|
||||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
|
||||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
|
||||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
|
||||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
|
||||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
|
||||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
|
||||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
|
||||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
|
||||||
|
|
||||||
/* Completeness */
|
|
||||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
|
||||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Task Master AI - Agent Integration Guide
|
# Task Master AI - Claude Code Integration Guide
|
||||||
|
|
||||||
## Essential Commands
|
## Essential Commands
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
# API Keys (Required to enable respective provider)
|
# API Keys (Required to enable respective provider)
|
||||||
ANTHROPIC_API_KEY="your_anthropic_api_key_here" # Required: Format: sk-ant-api03-...
|
ANTHROPIC_API_KEY="your_anthropic_api_key_here" # Required: Format: sk-ant-api03-...
|
||||||
PERPLEXITY_API_KEY="your_perplexity_api_key_here" # Optional: Format: pplx-...
|
PERPLEXITY_API_KEY="your_perplexity_api_key_here" # Optional: Format: pplx-...
|
||||||
OPENAI_API_KEY="your_openai_api_key_here" # Optional, for OpenAI models. Format: sk-proj-...
|
OPENAI_API_KEY="your_openai_api_key_here" # Optional, for OpenAI/OpenRouter models. Format: sk-proj-...
|
||||||
GOOGLE_API_KEY="your_google_api_key_here" # Optional, for Google Gemini models.
|
GOOGLE_API_KEY="your_google_api_key_here" # Optional, for Google Gemini models.
|
||||||
MISTRAL_API_KEY="your_mistral_key_here" # Optional, for Mistral AI models.
|
MISTRAL_API_KEY="your_mistral_key_here" # Optional, for Mistral AI models.
|
||||||
XAI_API_KEY="YOUR_XAI_KEY_HERE" # Optional, for xAI AI models.
|
XAI_API_KEY="YOUR_XAI_KEY_HERE" # Optional, for xAI AI models.
|
||||||
GROQ_API_KEY="YOUR_GROQ_KEY_HERE" # Optional, for Groq models.
|
|
||||||
OPENROUTER_API_KEY="YOUR_OPENROUTER_KEY_HERE" # Optional, for OpenRouter models.
|
|
||||||
AZURE_OPENAI_API_KEY="your_azure_key_here" # Optional, for Azure OpenAI models (requires endpoint in .taskmaster/config.json).
|
AZURE_OPENAI_API_KEY="your_azure_key_here" # Optional, for Azure OpenAI models (requires endpoint in .taskmaster/config.json).
|
||||||
OLLAMA_API_KEY="your_ollama_api_key_here" # Optional: For remote Ollama servers that require authentication.
|
OLLAMA_API_KEY="your_ollama_api_key_here" # Optional: For remote Ollama servers that require authentication.
|
||||||
GITHUB_API_KEY="your_github_api_key_here" # Optional: For GitHub import/export features. Format: ghp_... or github_pat_...
|
GITHUB_API_KEY="your_github_api_key_here" # Optional: For GitHub import/export features. Format: ghp_... or github_pat_...
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Available Models as of July 19, 2025
|
# Available Models as of July 10, 2025
|
||||||
|
|
||||||
## Main Models
|
## Main Models
|
||||||
|
|
||||||
@@ -32,7 +32,6 @@
|
|||||||
| xai | grok-3 | — | 3 | 15 |
|
| xai | grok-3 | — | 3 | 15 |
|
||||||
| xai | grok-3-fast | — | 5 | 25 |
|
| xai | grok-3-fast | — | 5 | 25 |
|
||||||
| xai | grok-4 | — | 3 | 15 |
|
| xai | grok-4 | — | 3 | 15 |
|
||||||
| groq | moonshotai/kimi-k2-instruct | 0.66 | 1 | 3 |
|
|
||||||
| groq | llama-3.3-70b-versatile | 0.55 | 0.59 | 0.79 |
|
| groq | llama-3.3-70b-versatile | 0.55 | 0.59 | 0.79 |
|
||||||
| groq | llama-3.1-8b-instant | 0.32 | 0.05 | 0.08 |
|
| groq | llama-3.1-8b-instant | 0.32 | 0.05 | 0.08 |
|
||||||
| groq | llama-4-scout | 0.45 | 0.11 | 0.34 |
|
| groq | llama-4-scout | 0.45 | 0.11 | 0.34 |
|
||||||
@@ -145,7 +144,6 @@
|
|||||||
| xai | grok-3 | — | 3 | 15 |
|
| xai | grok-3 | — | 3 | 15 |
|
||||||
| xai | grok-3-fast | — | 5 | 25 |
|
| xai | grok-3-fast | — | 5 | 25 |
|
||||||
| xai | grok-4 | — | 3 | 15 |
|
| xai | grok-4 | — | 3 | 15 |
|
||||||
| groq | moonshotai/kimi-k2-instruct | 0.66 | 1 | 3 |
|
|
||||||
| groq | llama-3.3-70b-versatile | 0.55 | 0.59 | 0.79 |
|
| groq | llama-3.3-70b-versatile | 0.55 | 0.59 | 0.79 |
|
||||||
| groq | llama-3.1-8b-instant | 0.32 | 0.05 | 0.08 |
|
| groq | llama-3.1-8b-instant | 0.32 | 0.05 | 0.08 |
|
||||||
| groq | llama-4-scout | 0.45 | 0.11 | 0.34 |
|
| groq | llama-4-scout | 0.45 | 0.11 | 0.34 |
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ import {
|
|||||||
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
||||||
* @param {string|number} args.id - Task ID to add dependency to
|
* @param {string|number} args.id - Task ID to add dependency to
|
||||||
* @param {string|number} args.dependsOn - Task ID that will become a dependency
|
* @param {string|number} args.dependsOn - Task ID that will become a dependency
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information
|
* @returns {Promise<Object>} - Result object with success status and data/error information
|
||||||
*/
|
*/
|
||||||
export async function addDependencyDirect(args, log) {
|
export async function addDependencyDirect(args, log) {
|
||||||
// Destructure expected args
|
// Destructure expected args
|
||||||
const { tasksJsonPath, id, dependsOn, tag, projectRoot } = args;
|
const { tasksJsonPath, id, dependsOn } = args;
|
||||||
try {
|
try {
|
||||||
log.info(`Adding dependency with args: ${JSON.stringify(args)}`);
|
log.info(`Adding dependency with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
@@ -78,11 +76,8 @@ export async function addDependencyDirect(args, log) {
|
|||||||
// Enable silent mode to prevent console logs from interfering with JSON response
|
// Enable silent mode to prevent console logs from interfering with JSON response
|
||||||
enableSilentMode();
|
enableSilentMode();
|
||||||
|
|
||||||
// Create context object
|
|
||||||
const context = { projectRoot, tag };
|
|
||||||
|
|
||||||
// Call the core function using the provided path
|
// Call the core function using the provided path
|
||||||
await addDependency(tasksPath, taskId, dependencyId, context);
|
await addDependency(tasksPath, taskId, dependencyId);
|
||||||
|
|
||||||
// Restore normal logging
|
// Restore normal logging
|
||||||
disableSilentMode();
|
disableSilentMode();
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
* @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
|
* @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
|
||||||
* @param {boolean} [args.research=false] - Whether to use research capabilities for task creation
|
* @param {boolean} [args.research=false] - Whether to use research capabilities for task creation
|
||||||
* @param {string} [args.projectRoot] - Project root path
|
* @param {string} [args.projectRoot] - Project root path
|
||||||
* @param {string} [args.tag] - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @param {Object} context - Additional context (session)
|
* @param {Object} context - Additional context (session)
|
||||||
* @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
|
* @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
|
||||||
@@ -37,8 +36,7 @@ export async function addTaskDirect(args, log, context = {}) {
|
|||||||
dependencies,
|
dependencies,
|
||||||
priority,
|
priority,
|
||||||
research,
|
research,
|
||||||
projectRoot,
|
projectRoot
|
||||||
tag
|
|
||||||
} = args;
|
} = args;
|
||||||
const { session } = context; // Destructure session from context
|
const { session } = context; // Destructure session from context
|
||||||
|
|
||||||
@@ -123,8 +121,7 @@ export async function addTaskDirect(args, log, context = {}) {
|
|||||||
mcpLog,
|
mcpLog,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
commandName: 'add-task',
|
commandName: 'add-task',
|
||||||
outputType: 'mcp',
|
outputType: 'mcp'
|
||||||
tag
|
|
||||||
},
|
},
|
||||||
'json', // outputFormat
|
'json', // outputFormat
|
||||||
manualTaskData, // Pass the manual task data
|
manualTaskData, // Pass the manual task data
|
||||||
@@ -150,8 +147,7 @@ export async function addTaskDirect(args, log, context = {}) {
|
|||||||
mcpLog,
|
mcpLog,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
commandName: 'add-task',
|
commandName: 'add-task',
|
||||||
outputType: 'mcp',
|
outputType: 'mcp'
|
||||||
tag
|
|
||||||
},
|
},
|
||||||
'json', // outputFormat
|
'json', // outputFormat
|
||||||
null, // manualTaskData is null for AI creation
|
null, // manualTaskData is null for AI creation
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import { createLogWrapper } from '../../tools/utils.js'; // Import the new utili
|
|||||||
* @param {number} [args.from] - Starting task ID in a range to analyze
|
* @param {number} [args.from] - Starting task ID in a range to analyze
|
||||||
* @param {number} [args.to] - Ending task ID in a range to analyze
|
* @param {number} [args.to] - Ending task ID in a range to analyze
|
||||||
* @param {string} [args.projectRoot] - Project root path.
|
* @param {string} [args.projectRoot] - Project root path.
|
||||||
* @param {string} [args.tag] - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @param {Object} [context={}] - Context object containing session data
|
* @param {Object} [context={}] - Context object containing session data
|
||||||
* @param {Object} [context.session] - MCP session object
|
* @param {Object} [context.session] - MCP session object
|
||||||
@@ -38,8 +37,7 @@ export async function analyzeTaskComplexityDirect(args, log, context = {}) {
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
ids,
|
ids,
|
||||||
from,
|
from,
|
||||||
to,
|
to
|
||||||
tag
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
const logWrapper = createLogWrapper(log);
|
const logWrapper = createLogWrapper(log);
|
||||||
@@ -93,8 +91,7 @@ export async function analyzeTaskComplexityDirect(args, log, context = {}) {
|
|||||||
projectRoot: projectRoot, // Pass projectRoot here
|
projectRoot: projectRoot, // Pass projectRoot here
|
||||||
id: ids, // Pass the ids parameter to the core function as 'id'
|
id: ids, // Pass the ids parameter to the core function as 'id'
|
||||||
from: from, // Pass from parameter
|
from: from, // Pass from parameter
|
||||||
to: to, // Pass to parameter
|
to: to // Pass to parameter
|
||||||
tag // forward tag
|
|
||||||
};
|
};
|
||||||
// --- End Initial Checks ---
|
// --- End Initial Checks ---
|
||||||
|
|
||||||
@@ -115,9 +112,7 @@ export async function analyzeTaskComplexityDirect(args, log, context = {}) {
|
|||||||
session,
|
session,
|
||||||
mcpLog: logWrapper,
|
mcpLog: logWrapper,
|
||||||
commandName: 'analyze-complexity',
|
commandName: 'analyze-complexity',
|
||||||
outputType: 'mcp',
|
outputType: 'mcp'
|
||||||
projectRoot,
|
|
||||||
tag
|
|
||||||
});
|
});
|
||||||
report = coreResult.report;
|
report = coreResult.report;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import path from 'path';
|
|||||||
* @param {string} [args.id] - Task IDs (comma-separated) to clear subtasks from
|
* @param {string} [args.id] - Task IDs (comma-separated) to clear subtasks from
|
||||||
* @param {boolean} [args.all] - Clear subtasks from all tasks
|
* @param {boolean} [args.all] - Clear subtasks from all tasks
|
||||||
* @param {string} [args.tag] - Tag context to operate on (defaults to current active tag)
|
* @param {string} [args.tag] - Tag context to operate on (defaults to current active tag)
|
||||||
* @param {string} [args.projectRoot] - Project root path (for MCP/env fallback)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
||||||
*/
|
*/
|
||||||
@@ -81,7 +80,7 @@ export async function clearSubtasksDirect(args, log) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentTag = data.tag || tag;
|
const currentTag = data.tag || 'master';
|
||||||
const tasks = data.tasks;
|
const tasks = data.tasks;
|
||||||
|
|
||||||
// If all is specified, get all task IDs
|
// If all is specified, get all task IDs
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
* @param {string} [args.prompt] - Additional context to guide subtask generation
|
* @param {string} [args.prompt] - Additional context to guide subtask generation
|
||||||
* @param {boolean} [args.force] - Force regeneration of subtasks for tasks that already have them
|
* @param {boolean} [args.force] - Force regeneration of subtasks for tasks that already have them
|
||||||
* @param {string} [args.projectRoot] - Project root path.
|
* @param {string} [args.projectRoot] - Project root path.
|
||||||
* @param {string} [args.tag] - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object from FastMCP
|
* @param {Object} log - Logger object from FastMCP
|
||||||
* @param {Object} context - Context object containing session
|
* @param {Object} context - Context object containing session
|
||||||
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
||||||
@@ -26,8 +25,7 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
export async function expandAllTasksDirect(args, log, context = {}) {
|
export async function expandAllTasksDirect(args, log, context = {}) {
|
||||||
const { session } = context; // Extract session
|
const { session } = context; // Extract session
|
||||||
// Destructure expected args, including projectRoot
|
// Destructure expected args, including projectRoot
|
||||||
const { tasksJsonPath, num, research, prompt, force, projectRoot, tag } =
|
const { tasksJsonPath, num, research, prompt, force, projectRoot } = args;
|
||||||
args;
|
|
||||||
|
|
||||||
// Create logger wrapper using the utility
|
// Create logger wrapper using the utility
|
||||||
const mcpLog = createLogWrapper(log);
|
const mcpLog = createLogWrapper(log);
|
||||||
@@ -46,7 +44,7 @@ export async function expandAllTasksDirect(args, log, context = {}) {
|
|||||||
enableSilentMode(); // Enable silent mode for the core function call
|
enableSilentMode(); // Enable silent mode for the core function call
|
||||||
try {
|
try {
|
||||||
log.info(
|
log.info(
|
||||||
`Calling core expandAllTasks with args: ${JSON.stringify({ num, research, prompt, force, projectRoot, tag })}`
|
`Calling core expandAllTasks with args: ${JSON.stringify({ num, research, prompt, force, projectRoot })}`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse parameters (ensure correct types)
|
// Parse parameters (ensure correct types)
|
||||||
@@ -62,7 +60,7 @@ export async function expandAllTasksDirect(args, log, context = {}) {
|
|||||||
useResearch,
|
useResearch,
|
||||||
additionalContext,
|
additionalContext,
|
||||||
forceFlag,
|
forceFlag,
|
||||||
{ session, mcpLog, projectRoot, tag },
|
{ session, mcpLog, projectRoot },
|
||||||
'json'
|
'json'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -35,17 +35,8 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
export async function expandTaskDirect(args, log, context = {}) {
|
export async function expandTaskDirect(args, log, context = {}) {
|
||||||
const { session } = context; // Extract session
|
const { session } = context; // Extract session
|
||||||
// Destructure expected args, including projectRoot
|
// Destructure expected args, including projectRoot
|
||||||
const {
|
const { tasksJsonPath, id, num, research, prompt, force, projectRoot, tag } =
|
||||||
tasksJsonPath,
|
args;
|
||||||
id,
|
|
||||||
num,
|
|
||||||
research,
|
|
||||||
prompt,
|
|
||||||
force,
|
|
||||||
projectRoot,
|
|
||||||
tag,
|
|
||||||
complexityReportPath
|
|
||||||
} = args;
|
|
||||||
|
|
||||||
// Log session root data for debugging
|
// Log session root data for debugging
|
||||||
log.info(
|
log.info(
|
||||||
@@ -201,7 +192,6 @@ export async function expandTaskDirect(args, log, context = {}) {
|
|||||||
useResearch,
|
useResearch,
|
||||||
additionalContext,
|
additionalContext,
|
||||||
{
|
{
|
||||||
complexityReportPath,
|
|
||||||
mcpLog,
|
mcpLog,
|
||||||
session,
|
session,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
|
|||||||
@@ -53,9 +53,10 @@ export async function fixDependenciesDirect(args, log) {
|
|||||||
// Enable silent mode to prevent console logs from interfering with JSON response
|
// Enable silent mode to prevent console logs from interfering with JSON response
|
||||||
enableSilentMode();
|
enableSilentMode();
|
||||||
|
|
||||||
const options = { projectRoot, tag };
|
|
||||||
// Call the original command function using the provided path and proper context
|
// Call the original command function using the provided path and proper context
|
||||||
await fixDependenciesCommand(tasksPath, options);
|
await fixDependenciesCommand(tasksPath, {
|
||||||
|
context: { projectRoot, tag }
|
||||||
|
});
|
||||||
|
|
||||||
// Restore normal logging
|
// Restore normal logging
|
||||||
disableSilentMode();
|
disableSilentMode();
|
||||||
|
|||||||
@@ -13,16 +13,12 @@ import {
|
|||||||
* Direct function wrapper for generateTaskFiles with error handling.
|
* Direct function wrapper for generateTaskFiles with error handling.
|
||||||
*
|
*
|
||||||
* @param {Object} args - Command arguments containing tasksJsonPath and outputDir.
|
* @param {Object} args - Command arguments containing tasksJsonPath and outputDir.
|
||||||
* @param {string} args.tasksJsonPath - Path to the tasks.json file.
|
|
||||||
* @param {string} args.outputDir - Path to the output directory.
|
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
*/
|
*/
|
||||||
export async function generateTaskFilesDirect(args, log) {
|
export async function generateTaskFilesDirect(args, log) {
|
||||||
// Destructure expected args
|
// Destructure expected args
|
||||||
const { tasksJsonPath, outputDir, projectRoot, tag } = args;
|
const { tasksJsonPath, outputDir } = args;
|
||||||
try {
|
try {
|
||||||
log.info(`Generating task files with args: ${JSON.stringify(args)}`);
|
log.info(`Generating task files with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
@@ -55,12 +51,8 @@ export async function generateTaskFilesDirect(args, log) {
|
|||||||
// Enable silent mode to prevent logs from being written to stdout
|
// Enable silent mode to prevent logs from being written to stdout
|
||||||
enableSilentMode();
|
enableSilentMode();
|
||||||
|
|
||||||
// Pass projectRoot and tag so the core respects context
|
// The function is synchronous despite being awaited elsewhere
|
||||||
generateTaskFiles(tasksPath, resolvedOutputDir, {
|
generateTaskFiles(tasksPath, resolvedOutputDir);
|
||||||
projectRoot,
|
|
||||||
tag,
|
|
||||||
mcpLog: log
|
|
||||||
});
|
|
||||||
|
|
||||||
// Restore normal logging after task generation
|
// Restore normal logging after task generation
|
||||||
disableSilentMode();
|
disableSilentMode();
|
||||||
|
|||||||
@@ -13,19 +13,12 @@ import {
|
|||||||
* Direct function wrapper for listTasks with error handling and caching.
|
* Direct function wrapper for listTasks with error handling and caching.
|
||||||
*
|
*
|
||||||
* @param {Object} args - Command arguments (now expecting tasksJsonPath explicitly).
|
* @param {Object} args - Command arguments (now expecting tasksJsonPath explicitly).
|
||||||
* @param {string} args.tasksJsonPath - Path to the tasks.json file.
|
|
||||||
* @param {string} args.reportPath - Path to the report file.
|
|
||||||
* @param {string} args.status - Status of the task.
|
|
||||||
* @param {boolean} args.withSubtasks - Whether to include subtasks.
|
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @returns {Promise<Object>} - Task list result { success: boolean, data?: any, error?: { code: string, message: string } }.
|
* @returns {Promise<Object>} - Task list result { success: boolean, data?: any, error?: { code: string, message: string } }.
|
||||||
*/
|
*/
|
||||||
export async function listTasksDirect(args, log, context = {}) {
|
export async function listTasksDirect(args, log, context = {}) {
|
||||||
// Destructure the explicit tasksJsonPath from args
|
// Destructure the explicit tasksJsonPath from args
|
||||||
const { tasksJsonPath, reportPath, status, withSubtasks, projectRoot, tag } =
|
const { tasksJsonPath, reportPath, status, withSubtasks, projectRoot } = args;
|
||||||
args;
|
|
||||||
const { session } = context;
|
const { session } = context;
|
||||||
|
|
||||||
if (!tasksJsonPath) {
|
if (!tasksJsonPath) {
|
||||||
@@ -59,7 +52,8 @@ export async function listTasksDirect(args, log, context = {}) {
|
|||||||
reportPath,
|
reportPath,
|
||||||
withSubtasksFilter,
|
withSubtasksFilter,
|
||||||
'json',
|
'json',
|
||||||
{ projectRoot, session, tag }
|
null, // tag
|
||||||
|
{ projectRoot, session } // context
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!resultData || !resultData.tasks) {
|
if (!resultData || !resultData.tasks) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ import {
|
|||||||
* @param {string} args.destinationId - ID of the destination (e.g., '7' or '7.3' or '7,8,9')
|
* @param {string} args.destinationId - ID of the destination (e.g., '7' or '7.3' or '7,8,9')
|
||||||
* @param {string} args.file - Alternative path to the tasks.json file
|
* @param {string} args.file - Alternative path to the tasks.json file
|
||||||
* @param {string} args.projectRoot - Project root directory
|
* @param {string} args.projectRoot - Project root directory
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {boolean} args.generateFiles - Whether to regenerate task files after moving (default: true)
|
* @param {boolean} args.generateFiles - Whether to regenerate task files after moving (default: true)
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<{success: boolean, data?: Object, error?: Object}>}
|
* @returns {Promise<{success: boolean, data?: Object, error?: Object}>}
|
||||||
*/
|
*/
|
||||||
export async function moveTaskDirect(args, log, context = {}) {
|
export async function moveTaskDirect(args, log, context = {}) {
|
||||||
const { session } = context;
|
const { session } = context;
|
||||||
const { projectRoot, tag } = args;
|
|
||||||
|
|
||||||
// Validate required parameters
|
// Validate required parameters
|
||||||
if (!args.sourceId) {
|
if (!args.sourceId) {
|
||||||
@@ -75,8 +73,8 @@ export async function moveTaskDirect(args, log, context = {}) {
|
|||||||
args.destinationId,
|
args.destinationId,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
{
|
{
|
||||||
projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag
|
tag: args.tag
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -18,15 +18,12 @@ import {
|
|||||||
*
|
*
|
||||||
* @param {Object} args - Command arguments
|
* @param {Object} args - Command arguments
|
||||||
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
||||||
* @param {string} args.reportPath - Path to the report file.
|
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<Object>} - Next task result { success: boolean, data?: any, error?: { code: string, message: string } }
|
* @returns {Promise<Object>} - Next task result { success: boolean, data?: any, error?: { code: string, message: string } }
|
||||||
*/
|
*/
|
||||||
export async function nextTaskDirect(args, log, context = {}) {
|
export async function nextTaskDirect(args, log, context = {}) {
|
||||||
// Destructure expected args
|
// Destructure expected args
|
||||||
const { tasksJsonPath, reportPath, projectRoot, tag } = args;
|
const { tasksJsonPath, reportPath, projectRoot } = args;
|
||||||
const { session } = context;
|
const { session } = context;
|
||||||
|
|
||||||
if (!tasksJsonPath) {
|
if (!tasksJsonPath) {
|
||||||
@@ -49,7 +46,7 @@ export async function nextTaskDirect(args, log, context = {}) {
|
|||||||
log.info(`Finding next task from ${tasksJsonPath}`);
|
log.info(`Finding next task from ${tasksJsonPath}`);
|
||||||
|
|
||||||
// Read tasks data using the provided path
|
// Read tasks data using the provided path
|
||||||
const data = readJSON(tasksJsonPath, projectRoot, tag);
|
const data = readJSON(tasksJsonPath, projectRoot);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
disableSilentMode(); // Disable before return
|
disableSilentMode(); // Disable before return
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -20,13 +20,6 @@ import { TASKMASTER_TASKS_FILE } from '../../../../src/constants/paths.js';
|
|||||||
* Direct function wrapper for parsing PRD documents and generating tasks.
|
* Direct function wrapper for parsing PRD documents and generating tasks.
|
||||||
*
|
*
|
||||||
* @param {Object} args - Command arguments containing projectRoot, input, output, numTasks options.
|
* @param {Object} args - Command arguments containing projectRoot, input, output, numTasks options.
|
||||||
* @param {string} args.input - Path to the input PRD file.
|
|
||||||
* @param {string} args.output - Path to the output directory.
|
|
||||||
* @param {string} args.numTasks - Number of tasks to generate.
|
|
||||||
* @param {boolean} args.force - Whether to force parsing.
|
|
||||||
* @param {boolean} args.append - Whether to append to the output file.
|
|
||||||
* @param {boolean} args.research - Whether to use research mode.
|
|
||||||
* @param {string} args.tag - Tag context for organizing tasks into separate task lists.
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @param {Object} context - Context object containing session data.
|
* @param {Object} context - Context object containing session data.
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
@@ -41,8 +34,7 @@ export async function parsePRDDirect(args, log, context = {}) {
|
|||||||
force,
|
force,
|
||||||
append,
|
append,
|
||||||
research,
|
research,
|
||||||
projectRoot,
|
projectRoot
|
||||||
tag
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
// Create the standard logger wrapper
|
// Create the standard logger wrapper
|
||||||
@@ -160,7 +152,6 @@ export async function parsePRDDirect(args, log, context = {}) {
|
|||||||
session,
|
session,
|
||||||
mcpLog: logWrapper,
|
mcpLog: logWrapper,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
tag,
|
|
||||||
force,
|
force,
|
||||||
append,
|
append,
|
||||||
research,
|
research,
|
||||||
|
|||||||
@@ -14,14 +14,12 @@ import {
|
|||||||
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
||||||
* @param {string|number} args.id - Task ID to remove dependency from
|
* @param {string|number} args.id - Task ID to remove dependency from
|
||||||
* @param {string|number} args.dependsOn - Task ID to remove as a dependency
|
* @param {string|number} args.dependsOn - Task ID to remove as a dependency
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
||||||
*/
|
*/
|
||||||
export async function removeDependencyDirect(args, log) {
|
export async function removeDependencyDirect(args, log) {
|
||||||
// Destructure expected args
|
// Destructure expected args
|
||||||
const { tasksJsonPath, id, dependsOn, projectRoot, tag } = args;
|
const { tasksJsonPath, id, dependsOn } = args;
|
||||||
try {
|
try {
|
||||||
log.info(`Removing dependency with args: ${JSON.stringify(args)}`);
|
log.info(`Removing dependency with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
@@ -77,10 +75,7 @@ export async function removeDependencyDirect(args, log) {
|
|||||||
enableSilentMode();
|
enableSilentMode();
|
||||||
|
|
||||||
// Call the core function using the provided tasksPath
|
// Call the core function using the provided tasksPath
|
||||||
await removeDependency(tasksPath, taskId, dependencyId, {
|
await removeDependency(tasksPath, taskId, dependencyId);
|
||||||
projectRoot,
|
|
||||||
tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// Restore normal logging
|
// Restore normal logging
|
||||||
disableSilentMode();
|
disableSilentMode();
|
||||||
|
|||||||
@@ -15,14 +15,12 @@ import {
|
|||||||
* @param {string} args.id - Subtask ID in format "parentId.subtaskId" (required)
|
* @param {string} args.id - Subtask ID in format "parentId.subtaskId" (required)
|
||||||
* @param {boolean} [args.convert] - Whether to convert the subtask to a standalone task
|
* @param {boolean} [args.convert] - Whether to convert the subtask to a standalone task
|
||||||
* @param {boolean} [args.skipGenerate] - Skip regenerating task files
|
* @param {boolean} [args.skipGenerate] - Skip regenerating task files
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
||||||
*/
|
*/
|
||||||
export async function removeSubtaskDirect(args, log) {
|
export async function removeSubtaskDirect(args, log) {
|
||||||
// Destructure expected args
|
// Destructure expected args
|
||||||
const { tasksJsonPath, id, convert, skipGenerate, projectRoot, tag } = args;
|
const { tasksJsonPath, id, convert, skipGenerate } = args;
|
||||||
try {
|
try {
|
||||||
// Enable silent mode to prevent console logs from interfering with JSON response
|
// Enable silent mode to prevent console logs from interfering with JSON response
|
||||||
enableSilentMode();
|
enableSilentMode();
|
||||||
@@ -84,11 +82,7 @@ export async function removeSubtaskDirect(args, log) {
|
|||||||
tasksPath,
|
tasksPath,
|
||||||
id,
|
id,
|
||||||
convertToTask,
|
convertToTask,
|
||||||
generateFiles,
|
generateFiles
|
||||||
{
|
|
||||||
projectRoot,
|
|
||||||
tag
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Restore normal logging
|
// Restore normal logging
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ import {
|
|||||||
* @param {Object} args - Command arguments
|
* @param {Object} args - Command arguments
|
||||||
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
||||||
* @param {string} args.id - The ID(s) of the task(s) or subtask(s) to remove (comma-separated for multiple).
|
* @param {string} args.id - The ID(s) of the task(s) or subtask(s) to remove (comma-separated for multiple).
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
* @param {string} [args.tag] - Tag context to operate on (defaults to current active tag).
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<Object>} - Remove task result { success: boolean, data?: any, error?: { code: string, message: string } }
|
* @returns {Promise<Object>} - Remove task result { success: boolean, data?: any, error?: { code: string, message: string } }
|
||||||
*/
|
*/
|
||||||
@@ -118,7 +117,7 @@ export async function removeTaskDirect(args, log, context = {}) {
|
|||||||
removedTasks: result.removedTasks,
|
removedTasks: result.removedTasks,
|
||||||
message: result.message,
|
message: result.message,
|
||||||
tasksPath: tasksJsonPath,
|
tasksPath: tasksJsonPath,
|
||||||
tag
|
tag: data.tag || tag || 'master'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
* @param {string} [args.saveTo] - Automatically save to task/subtask ID (e.g., "15" or "15.2")
|
* @param {string} [args.saveTo] - Automatically save to task/subtask ID (e.g., "15" or "15.2")
|
||||||
* @param {boolean} [args.saveToFile=false] - Save research results to .taskmaster/docs/research/ directory
|
* @param {boolean} [args.saveToFile=false] - Save research results to .taskmaster/docs/research/ directory
|
||||||
* @param {string} [args.projectRoot] - Project root path
|
* @param {string} [args.projectRoot] - Project root path
|
||||||
* @param {string} [args.tag] - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @param {Object} context - Additional context (session)
|
* @param {Object} context - Additional context (session)
|
||||||
* @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
|
* @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
|
||||||
@@ -40,8 +39,7 @@ export async function researchDirect(args, log, context = {}) {
|
|||||||
detailLevel = 'medium',
|
detailLevel = 'medium',
|
||||||
saveTo,
|
saveTo,
|
||||||
saveToFile = false,
|
saveToFile = false,
|
||||||
projectRoot,
|
projectRoot
|
||||||
tag
|
|
||||||
} = args;
|
} = args;
|
||||||
const { session } = context; // Destructure session from context
|
const { session } = context; // Destructure session from context
|
||||||
|
|
||||||
@@ -113,7 +111,6 @@ export async function researchDirect(args, log, context = {}) {
|
|||||||
includeProjectTree,
|
includeProjectTree,
|
||||||
detailLevel,
|
detailLevel,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
tag,
|
|
||||||
saveToFile
|
saveToFile
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -172,8 +169,7 @@ ${result.result}`;
|
|||||||
mcpLog,
|
mcpLog,
|
||||||
commandName: 'research-save',
|
commandName: 'research-save',
|
||||||
outputType: 'mcp',
|
outputType: 'mcp',
|
||||||
projectRoot,
|
projectRoot
|
||||||
tag
|
|
||||||
},
|
},
|
||||||
'json'
|
'json'
|
||||||
);
|
);
|
||||||
@@ -204,8 +200,7 @@ ${result.result}`;
|
|||||||
mcpLog,
|
mcpLog,
|
||||||
commandName: 'research-save',
|
commandName: 'research-save',
|
||||||
outputType: 'mcp',
|
outputType: 'mcp',
|
||||||
projectRoot,
|
projectRoot
|
||||||
tag
|
|
||||||
},
|
},
|
||||||
'json',
|
'json',
|
||||||
true // appendMode = true
|
true // appendMode = true
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ import { nextTaskDirect } from './next-task.js';
|
|||||||
* Direct function wrapper for setTaskStatus with error handling.
|
* Direct function wrapper for setTaskStatus with error handling.
|
||||||
*
|
*
|
||||||
* @param {Object} args - Command arguments containing id, status, tasksJsonPath, and projectRoot.
|
* @param {Object} args - Command arguments containing id, status, tasksJsonPath, and projectRoot.
|
||||||
* @param {string} args.id - The ID of the task to update.
|
|
||||||
* @param {string} args.status - The new status to set for the task.
|
|
||||||
* @param {string} args.tasksJsonPath - Path to the tasks.json file.
|
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @param {Object} context - Additional context (session)
|
* @param {Object} context - Additional context (session)
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
@@ -75,12 +70,17 @@ export async function setTaskStatusDirect(args, log, context = {}) {
|
|||||||
enableSilentMode(); // Enable silent mode before calling core function
|
enableSilentMode(); // Enable silent mode before calling core function
|
||||||
try {
|
try {
|
||||||
// Call the core function
|
// Call the core function
|
||||||
await setTaskStatus(tasksPath, taskId, newStatus, {
|
await setTaskStatus(
|
||||||
mcpLog: log,
|
tasksPath,
|
||||||
projectRoot,
|
taskId,
|
||||||
session,
|
newStatus,
|
||||||
|
{
|
||||||
|
mcpLog: log,
|
||||||
|
projectRoot,
|
||||||
|
session
|
||||||
|
},
|
||||||
tag
|
tag
|
||||||
});
|
);
|
||||||
|
|
||||||
log.info(`Successfully set task ${taskId} status to ${newStatus}`);
|
log.info(`Successfully set task ${taskId} status to ${newStatus}`);
|
||||||
|
|
||||||
@@ -103,8 +103,7 @@ export async function setTaskStatusDirect(args, log, context = {}) {
|
|||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
reportPath: complexityReportPath,
|
reportPath: complexityReportPath,
|
||||||
projectRoot: projectRoot,
|
projectRoot: projectRoot
|
||||||
tag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import { findTasksPath } from '../utils/path-utils.js';
|
|||||||
* @param {string} args.reportPath - Explicit path to the complexity report file.
|
* @param {string} args.reportPath - Explicit path to the complexity report file.
|
||||||
* @param {string} [args.status] - Optional status to filter subtasks by.
|
* @param {string} [args.status] - Optional status to filter subtasks by.
|
||||||
* @param {string} args.projectRoot - Absolute path to the project root directory (already normalized by tool).
|
* @param {string} args.projectRoot - Absolute path to the project root directory (already normalized by tool).
|
||||||
* @param {string} [args.tag] - Tag for the task
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @param {Object} context - Context object containing session data.
|
* @param {Object} context - Context object containing session data.
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
@@ -27,7 +26,7 @@ import { findTasksPath } from '../utils/path-utils.js';
|
|||||||
export async function showTaskDirect(args, log) {
|
export async function showTaskDirect(args, log) {
|
||||||
// This function doesn't need session context since it only reads data
|
// This function doesn't need session context since it only reads data
|
||||||
// Destructure projectRoot and other args. projectRoot is assumed normalized.
|
// Destructure projectRoot and other args. projectRoot is assumed normalized.
|
||||||
const { id, file, reportPath, status, projectRoot, tag } = args;
|
const { id, file, reportPath, status, projectRoot } = args;
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`Showing task direct function. ID: ${id}, File: ${file}, Status Filter: ${status}, ProjectRoot: ${projectRoot}`
|
`Showing task direct function. ID: ${id}, File: ${file}, Status Filter: ${status}, ProjectRoot: ${projectRoot}`
|
||||||
@@ -56,7 +55,7 @@ export async function showTaskDirect(args, log) {
|
|||||||
|
|
||||||
// --- Rest of the function remains the same, using tasksJsonPath ---
|
// --- Rest of the function remains the same, using tasksJsonPath ---
|
||||||
try {
|
try {
|
||||||
const tasksData = readJSON(tasksJsonPath, projectRoot, tag);
|
const tasksData = readJSON(tasksJsonPath, projectRoot);
|
||||||
if (!tasksData || !tasksData.tasks) {
|
if (!tasksData || !tasksData.tasks) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
* @param {string} args.prompt - Information to append to the subtask.
|
* @param {string} args.prompt - Information to append to the subtask.
|
||||||
* @param {boolean} [args.research] - Whether to use research role.
|
* @param {boolean} [args.research] - Whether to use research role.
|
||||||
* @param {string} [args.projectRoot] - Project root path.
|
* @param {string} [args.projectRoot] - Project root path.
|
||||||
* @param {string} [args.tag] - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @param {Object} context - Context object containing session data.
|
* @param {Object} context - Context object containing session data.
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
@@ -28,7 +27,7 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
export async function updateSubtaskByIdDirect(args, log, context = {}) {
|
export async function updateSubtaskByIdDirect(args, log, context = {}) {
|
||||||
const { session } = context;
|
const { session } = context;
|
||||||
// Destructure expected args, including projectRoot
|
// Destructure expected args, including projectRoot
|
||||||
const { tasksJsonPath, id, prompt, research, projectRoot, tag } = args;
|
const { tasksJsonPath, id, prompt, research, projectRoot } = args;
|
||||||
|
|
||||||
const logWrapper = createLogWrapper(log);
|
const logWrapper = createLogWrapper(log);
|
||||||
|
|
||||||
@@ -113,7 +112,6 @@ export async function updateSubtaskByIdDirect(args, log, context = {}) {
|
|||||||
mcpLog: logWrapper,
|
mcpLog: logWrapper,
|
||||||
session,
|
session,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
tag,
|
|
||||||
commandName: 'update-subtask',
|
commandName: 'update-subtask',
|
||||||
outputType: 'mcp'
|
outputType: 'mcp'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
* @param {boolean} [args.research] - Whether to use research role.
|
* @param {boolean} [args.research] - Whether to use research role.
|
||||||
* @param {boolean} [args.append] - Whether to append timestamped information instead of full update.
|
* @param {boolean} [args.append] - Whether to append timestamped information instead of full update.
|
||||||
* @param {string} [args.projectRoot] - Project root path.
|
* @param {string} [args.projectRoot] - Project root path.
|
||||||
* @param {string} [args.tag] - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @param {Object} context - Context object containing session data.
|
* @param {Object} context - Context object containing session data.
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
@@ -29,8 +28,7 @@ import { createLogWrapper } from '../../tools/utils.js';
|
|||||||
export async function updateTaskByIdDirect(args, log, context = {}) {
|
export async function updateTaskByIdDirect(args, log, context = {}) {
|
||||||
const { session } = context;
|
const { session } = context;
|
||||||
// Destructure expected args, including projectRoot
|
// Destructure expected args, including projectRoot
|
||||||
const { tasksJsonPath, id, prompt, research, append, projectRoot, tag } =
|
const { tasksJsonPath, id, prompt, research, append, projectRoot } = args;
|
||||||
args;
|
|
||||||
|
|
||||||
const logWrapper = createLogWrapper(log);
|
const logWrapper = createLogWrapper(log);
|
||||||
|
|
||||||
@@ -118,7 +116,6 @@ export async function updateTaskByIdDirect(args, log, context = {}) {
|
|||||||
mcpLog: logWrapper,
|
mcpLog: logWrapper,
|
||||||
session,
|
session,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
tag,
|
|
||||||
commandName: 'update-task',
|
commandName: 'update-task',
|
||||||
outputType: 'mcp'
|
outputType: 'mcp'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ import {
|
|||||||
* Direct function wrapper for updating tasks based on new context.
|
* Direct function wrapper for updating tasks based on new context.
|
||||||
*
|
*
|
||||||
* @param {Object} args - Command arguments containing projectRoot, from, prompt, research options.
|
* @param {Object} args - Command arguments containing projectRoot, from, prompt, research options.
|
||||||
* @param {string} args.from - The ID of the task to update.
|
|
||||||
* @param {string} args.prompt - The prompt to update the task with.
|
|
||||||
* @param {boolean} args.research - Whether to use research mode.
|
|
||||||
* @param {string} args.tasksJsonPath - Path to the tasks.json file.
|
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object.
|
* @param {Object} log - Logger object.
|
||||||
* @param {Object} context - Context object containing session data.
|
* @param {Object} context - Context object containing session data.
|
||||||
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
|
|||||||
@@ -13,14 +13,12 @@ import fs from 'fs';
|
|||||||
* Validate dependencies in tasks.json
|
* Validate dependencies in tasks.json
|
||||||
* @param {Object} args - Function arguments
|
* @param {Object} args - Function arguments
|
||||||
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
* @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
|
||||||
* @param {string} args.projectRoot - Project root path (for MCP/env fallback)
|
|
||||||
* @param {string} args.tag - Tag for the task (optional)
|
|
||||||
* @param {Object} log - Logger object
|
* @param {Object} log - Logger object
|
||||||
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
* @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
|
||||||
*/
|
*/
|
||||||
export async function validateDependenciesDirect(args, log) {
|
export async function validateDependenciesDirect(args, log) {
|
||||||
// Destructure the explicit tasksJsonPath
|
// Destructure the explicit tasksJsonPath
|
||||||
const { tasksJsonPath, projectRoot, tag } = args;
|
const { tasksJsonPath } = args;
|
||||||
|
|
||||||
if (!tasksJsonPath) {
|
if (!tasksJsonPath) {
|
||||||
log.error('validateDependenciesDirect called without tasksJsonPath');
|
log.error('validateDependenciesDirect called without tasksJsonPath');
|
||||||
@@ -53,9 +51,8 @@ export async function validateDependenciesDirect(args, log) {
|
|||||||
// Enable silent mode to prevent console logs from interfering with JSON response
|
// Enable silent mode to prevent console logs from interfering with JSON response
|
||||||
enableSilentMode();
|
enableSilentMode();
|
||||||
|
|
||||||
const options = { projectRoot, tag };
|
|
||||||
// Call the original command function using the provided tasksPath
|
// Call the original command function using the provided tasksPath
|
||||||
await validateDependenciesCommand(tasksPath, options);
|
await validateDependenciesCommand(tasksPath);
|
||||||
|
|
||||||
// Restore normal logging
|
// Restore normal logging
|
||||||
disableSilentMode();
|
disableSilentMode();
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ export function resolveComplexityReportPath(args, log = silentLogger) {
|
|||||||
// Get explicit path from args.complexityReport if provided
|
// Get explicit path from args.complexityReport if provided
|
||||||
const explicitPath = args?.complexityReport;
|
const explicitPath = args?.complexityReport;
|
||||||
const rawProjectRoot = args?.projectRoot;
|
const rawProjectRoot = args?.projectRoot;
|
||||||
const tag = args?.tag;
|
|
||||||
|
|
||||||
// If explicit path is provided and absolute, use it directly
|
// If explicit path is provided and absolute, use it directly
|
||||||
if (explicitPath && path.isAbsolute(explicitPath)) {
|
if (explicitPath && path.isAbsolute(explicitPath)) {
|
||||||
@@ -140,11 +139,7 @@ export function resolveComplexityReportPath(args, log = silentLogger) {
|
|||||||
|
|
||||||
// Use core findComplexityReportPath with explicit path and normalized projectRoot context
|
// Use core findComplexityReportPath with explicit path and normalized projectRoot context
|
||||||
if (projectRoot) {
|
if (projectRoot) {
|
||||||
return coreFindComplexityReportPath(
|
return coreFindComplexityReportPath(explicitPath, { projectRoot }, log);
|
||||||
explicitPath,
|
|
||||||
{ projectRoot, tag },
|
|
||||||
log
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to core function without projectRoot context
|
// Fallback to core function without projectRoot context
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ class TaskMasterMCPServer {
|
|||||||
this.server = new FastMCP(this.options);
|
this.server = new FastMCP(this.options);
|
||||||
this.initialized = false;
|
this.initialized = false;
|
||||||
|
|
||||||
|
this.server.addResource({});
|
||||||
|
|
||||||
|
this.server.addResourceTemplate({});
|
||||||
|
|
||||||
// Bind methods
|
// Bind methods
|
||||||
this.init = this.init.bind(this);
|
this.init = this.init.bind(this);
|
||||||
this.start = this.start.bind(this);
|
this.start = this.start.bind(this);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { addDependencyDirect } from '../core/task-master-core.js';
|
import { addDependencyDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the addDependency tool with the MCP server
|
* Register the addDependency tool with the MCP server
|
||||||
@@ -34,18 +33,14 @@ export function registerAddDependencyTool(server) {
|
|||||||
),
|
),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
log.info(
|
log.info(
|
||||||
`Adding dependency for task ${args.id} to depend on ${args.dependsOn}`
|
`Adding dependency for task ${args.id} to depend on ${args.dependsOn}`
|
||||||
);
|
);
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
tasksJsonPath = findTasksPath(
|
tasksJsonPath = findTasksPath(
|
||||||
@@ -66,9 +61,7 @@ export function registerAddDependencyTool(server) {
|
|||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
// Pass other relevant args
|
// Pass other relevant args
|
||||||
id: args.id,
|
id: args.id,
|
||||||
dependsOn: args.dependsOn,
|
dependsOn: args.dependsOn
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log
|
log
|
||||||
// Remove context object
|
// Remove context object
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { addSubtaskDirect } from '../core/task-master-core.js';
|
import { addSubtaskDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the addSubtask tool with the MCP server
|
* Register the addSubtask tool with the MCP server
|
||||||
@@ -53,21 +52,17 @@ export function registerAddSubtaskTool(server) {
|
|||||||
.describe(
|
.describe(
|
||||||
'Absolute path to the tasks file (default: tasks/tasks.json)'
|
'Absolute path to the tasks file (default: tasks/tasks.json)'
|
||||||
),
|
),
|
||||||
|
tag: z.string().optional().describe('Tag context to operate on'),
|
||||||
skipGenerate: z
|
skipGenerate: z
|
||||||
.boolean()
|
.boolean()
|
||||||
.optional()
|
.optional()
|
||||||
.describe('Skip regenerating task files'),
|
.describe('Skip regenerating task files'),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
log.info(`Adding subtask with args: ${JSON.stringify(args)}`);
|
log.info(`Adding subtask with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
@@ -96,7 +91,7 @@ export function registerAddSubtaskTool(server) {
|
|||||||
dependencies: args.dependencies,
|
dependencies: args.dependencies,
|
||||||
skipGenerate: args.skipGenerate,
|
skipGenerate: args.skipGenerate,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag
|
tag: args.tag
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { addTaskDirect } from '../core/task-master-core.js';
|
import { addTaskDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the addTask tool with the MCP server
|
* Register the addTask tool with the MCP server
|
||||||
@@ -59,7 +58,6 @@ export function registerAddTaskTool(server) {
|
|||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.'),
|
||||||
tag: z.string().optional().describe('Tag context to operate on'),
|
|
||||||
research: z
|
research: z
|
||||||
.boolean()
|
.boolean()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -69,11 +67,6 @@ export function registerAddTaskTool(server) {
|
|||||||
try {
|
try {
|
||||||
log.info(`Starting add-task with args: ${JSON.stringify(args)}`);
|
log.info(`Starting add-task with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -100,8 +93,7 @@ export function registerAddTaskTool(server) {
|
|||||||
dependencies: args.dependencies,
|
dependencies: args.dependencies,
|
||||||
priority: args.priority,
|
priority: args.priority,
|
||||||
research: args.research,
|
research: args.research,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { analyzeTaskComplexityDirect } from '../core/task-master-core.js'; // Assuming core functions are exported via task-master-core.js
|
import { analyzeTaskComplexityDirect } from '../core/task-master-core.js'; // Assuming core functions are exported via task-master-core.js
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
import { COMPLEXITY_REPORT_FILE } from '../../../src/constants/paths.js';
|
import { COMPLEXITY_REPORT_FILE } from '../../../src/constants/paths.js';
|
||||||
import { resolveComplexityReportOutputPath } from '../../../src/utils/path-utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the analyze_project_complexity tool
|
* Register the analyze_project_complexity tool
|
||||||
@@ -72,22 +70,15 @@ export function registerAnalyzeProjectComplexityTool(server) {
|
|||||||
.describe('Ending task ID in a range to analyze.'),
|
.describe('Ending task ID in a range to analyze.'),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
const toolName = 'analyze_project_complexity'; // Define tool name for logging
|
const toolName = 'analyze_project_complexity'; // Define tool name for logging
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.info(
|
log.info(
|
||||||
`Executing ${toolName} tool with args: ${JSON.stringify(args)}`
|
`Executing ${toolName} tool with args: ${JSON.stringify(args)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
tasksJsonPath = findTasksPath(
|
tasksJsonPath = findTasksPath(
|
||||||
@@ -102,14 +93,9 @@ export function registerAnalyzeProjectComplexityTool(server) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputPath = resolveComplexityReportOutputPath(
|
const outputPath = args.output
|
||||||
args.output,
|
? path.resolve(args.projectRoot, args.output)
|
||||||
{
|
: path.resolve(args.projectRoot, COMPLEXITY_REPORT_FILE);
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: resolvedTag
|
|
||||||
},
|
|
||||||
log
|
|
||||||
);
|
|
||||||
|
|
||||||
log.info(`${toolName}: Report output path: ${outputPath}`);
|
log.info(`${toolName}: Report output path: ${outputPath}`);
|
||||||
|
|
||||||
@@ -137,7 +123,6 @@ export function registerAnalyzeProjectComplexityTool(server) {
|
|||||||
threshold: args.threshold,
|
threshold: args.threshold,
|
||||||
research: args.research,
|
research: args.research,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag,
|
|
||||||
ids: args.ids,
|
ids: args.ids,
|
||||||
from: args.from,
|
from: args.from,
|
||||||
to: args.to
|
to: args.to
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { clearSubtasksDirect } from '../core/task-master-core.js';
|
import { clearSubtasksDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the clearSubtasks tool with the MCP server
|
* Register the clearSubtasks tool with the MCP server
|
||||||
@@ -47,11 +46,6 @@ export function registerClearSubtasksTool(server) {
|
|||||||
try {
|
try {
|
||||||
log.info(`Clearing subtasks with args: ${JSON.stringify(args)}`);
|
log.info(`Clearing subtasks with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -71,9 +65,8 @@ export function registerClearSubtasksTool(server) {
|
|||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
id: args.id,
|
id: args.id,
|
||||||
all: args.all,
|
all: args.all,
|
||||||
|
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag
|
tag: args.tag || 'master'
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import {
|
|||||||
import { complexityReportDirect } from '../core/task-master-core.js';
|
import { complexityReportDirect } from '../core/task-master-core.js';
|
||||||
import { COMPLEXITY_REPORT_FILE } from '../../../src/constants/paths.js';
|
import { COMPLEXITY_REPORT_FILE } from '../../../src/constants/paths.js';
|
||||||
import { findComplexityReportPath } from '../core/utils/path-utils.js';
|
import { findComplexityReportPath } from '../core/utils/path-utils.js';
|
||||||
import { getCurrentTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the complexityReport tool with the MCP server
|
* Register the complexityReport tool with the MCP server
|
||||||
@@ -39,16 +38,12 @@ export function registerComplexityReportTool(server) {
|
|||||||
`Getting complexity report with args: ${JSON.stringify(args)}`
|
`Getting complexity report with args: ${JSON.stringify(args)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const resolvedTag = getCurrentTag(args.projectRoot);
|
|
||||||
|
|
||||||
const pathArgs = {
|
const pathArgs = {
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
complexityReport: args.file,
|
complexityReport: args.file
|
||||||
tag: resolvedTag
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const reportPath = findComplexityReportPath(pathArgs, log);
|
const reportPath = findComplexityReportPath(pathArgs, log);
|
||||||
log.info('Reading complexity report from path: ', reportPath);
|
|
||||||
|
|
||||||
if (!reportPath) {
|
if (!reportPath) {
|
||||||
return createErrorResponse(
|
return createErrorResponse(
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { expandAllTasksDirect } from '../core/task-master-core.js';
|
import { expandAllTasksDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the expandAll tool with the MCP server
|
* Register the expandAll tool with the MCP server
|
||||||
@@ -58,8 +57,7 @@ export function registerExpandAllTool(server) {
|
|||||||
.optional()
|
.optional()
|
||||||
.describe(
|
.describe(
|
||||||
'Absolute path to the project root directory (derived from session if possible)'
|
'Absolute path to the project root directory (derived from session if possible)'
|
||||||
),
|
)
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
@@ -67,10 +65,6 @@ export function registerExpandAllTool(server) {
|
|||||||
`Tool expand_all execution started with args: ${JSON.stringify(args)}`
|
`Tool expand_all execution started with args: ${JSON.stringify(args)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
tasksJsonPath = findTasksPath(
|
tasksJsonPath = findTasksPath(
|
||||||
@@ -92,8 +86,7 @@ export function registerExpandAllTool(server) {
|
|||||||
research: args.research,
|
research: args.research,
|
||||||
prompt: args.prompt,
|
prompt: args.prompt,
|
||||||
force: args.force,
|
force: args.force,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -10,11 +10,7 @@ import {
|
|||||||
withNormalizedProjectRoot
|
withNormalizedProjectRoot
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { expandTaskDirect } from '../core/task-master-core.js';
|
import { expandTaskDirect } from '../core/task-master-core.js';
|
||||||
import {
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
findTasksPath,
|
|
||||||
findComplexityReportPath
|
|
||||||
} from '../core/utils/path-utils.js';
|
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the expand-task tool with the MCP server
|
* Register the expand-task tool with the MCP server
|
||||||
@@ -55,10 +51,7 @@ export function registerExpandTaskTool(server) {
|
|||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
log.info(`Starting expand-task with args: ${JSON.stringify(args)}`);
|
log.info(`Starting expand-task with args: ${JSON.stringify(args)}`);
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -73,11 +66,6 @@ export function registerExpandTaskTool(server) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const complexityReportPath = findComplexityReportPath(
|
|
||||||
{ ...args, tag: resolvedTag },
|
|
||||||
log
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await expandTaskDirect(
|
const result = await expandTaskDirect(
|
||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
@@ -86,9 +74,8 @@ export function registerExpandTaskTool(server) {
|
|||||||
research: args.research,
|
research: args.research,
|
||||||
prompt: args.prompt,
|
prompt: args.prompt,
|
||||||
force: args.force,
|
force: args.force,
|
||||||
complexityReportPath,
|
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag
|
tag: args.tag || 'master'
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { fixDependenciesDirect } from '../core/task-master-core.js';
|
import { fixDependenciesDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
/**
|
/**
|
||||||
* Register the fixDependencies tool with the MCP server
|
* Register the fixDependencies tool with the MCP server
|
||||||
* @param {Object} server - FastMCP server instance
|
* @param {Object} server - FastMCP server instance
|
||||||
@@ -31,11 +31,6 @@ export function registerFixDependenciesTool(server) {
|
|||||||
try {
|
try {
|
||||||
log.info(`Fixing dependencies with args: ${JSON.stringify(args)}`);
|
log.info(`Fixing dependencies with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -54,7 +49,7 @@ export function registerFixDependenciesTool(server) {
|
|||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag
|
tag: args.tag
|
||||||
},
|
},
|
||||||
log
|
log
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { generateTaskFilesDirect } from '../core/task-master-core.js';
|
import { generateTaskFilesDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,17 +30,12 @@ export function registerGenerateTool(server) {
|
|||||||
.describe('Output directory (default: same directory as tasks file)'),
|
.describe('Output directory (default: same directory as tasks file)'),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
log.info(`Generating task files with args: ${JSON.stringify(args)}`);
|
log.info(`Generating task files with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -64,8 +58,7 @@ export function registerGenerateTool(server) {
|
|||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
outputDir: outputDir,
|
outputDir: outputDir,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
findTasksPath,
|
findTasksPath,
|
||||||
findComplexityReportPath
|
findComplexityReportPath
|
||||||
} from '../core/utils/path-utils.js';
|
} from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom processor function that removes allTasks from the response
|
* Custom processor function that removes allTasks from the response
|
||||||
@@ -68,8 +67,7 @@ export function registerShowTaskTool(server) {
|
|||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe(
|
||||||
'Absolute path to the project root directory (Optional, usually from session)'
|
'Absolute path to the project root directory (Optional, usually from session)'
|
||||||
),
|
)
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
const { id, file, status, projectRoot } = args;
|
const { id, file, status, projectRoot } = args;
|
||||||
@@ -78,10 +76,6 @@ export function registerShowTaskTool(server) {
|
|||||||
log.info(
|
log.info(
|
||||||
`Getting task details for ID: ${id}${status ? ` (filtering subtasks by status: ${status})` : ''} in root: ${projectRoot}`
|
`Getting task details for ID: ${id}${status ? ` (filtering subtasks by status: ${status})` : ''} in root: ${projectRoot}`
|
||||||
);
|
);
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// Resolve the path to tasks.json using the NORMALIZED projectRoot from args
|
// Resolve the path to tasks.json using the NORMALIZED projectRoot from args
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
@@ -105,8 +99,7 @@ export function registerShowTaskTool(server) {
|
|||||||
complexityReportPath = findComplexityReportPath(
|
complexityReportPath = findComplexityReportPath(
|
||||||
{
|
{
|
||||||
projectRoot: projectRoot,
|
projectRoot: projectRoot,
|
||||||
complexityReport: args.complexityReport,
|
complexityReport: args.complexityReport
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log
|
log
|
||||||
);
|
);
|
||||||
@@ -120,8 +113,7 @@ export function registerShowTaskTool(server) {
|
|||||||
// Pass other relevant args
|
// Pass other relevant args
|
||||||
id: id,
|
id: id,
|
||||||
status: status,
|
status: status,
|
||||||
projectRoot: projectRoot,
|
projectRoot: projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import {
|
|||||||
resolveComplexityReportPath
|
resolveComplexityReportPath
|
||||||
} from '../core/utils/path-utils.js';
|
} from '../core/utils/path-utils.js';
|
||||||
|
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the getTasks tool with the MCP server
|
* Register the getTasks tool with the MCP server
|
||||||
* @param {Object} server - FastMCP server instance
|
* @param {Object} server - FastMCP server instance
|
||||||
@@ -53,17 +51,12 @@ export function registerListTasksTool(server) {
|
|||||||
),
|
),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
log.info(`Getting tasks with filters: ${JSON.stringify(args)}`);
|
log.info(`Getting tasks with filters: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
// Resolve the path to tasks.json using new path utilities
|
// Resolve the path to tasks.json using new path utilities
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -78,10 +71,7 @@ export function registerListTasksTool(server) {
|
|||||||
// Resolve the path to complexity report
|
// Resolve the path to complexity report
|
||||||
let complexityReportPath;
|
let complexityReportPath;
|
||||||
try {
|
try {
|
||||||
complexityReportPath = resolveComplexityReportPath(
|
complexityReportPath = resolveComplexityReportPath(args, session);
|
||||||
{ ...args, tag: resolvedTag },
|
|
||||||
session
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error finding complexity report: ${error.message}`);
|
log.error(`Error finding complexity report: ${error.message}`);
|
||||||
// This is optional, so we don't fail the operation
|
// This is optional, so we don't fail the operation
|
||||||
@@ -94,8 +84,7 @@ export function registerListTasksTool(server) {
|
|||||||
status: args.status,
|
status: args.status,
|
||||||
withSubtasks: args.withSubtasks,
|
withSubtasks: args.withSubtasks,
|
||||||
reportPath: complexityReportPath,
|
reportPath: complexityReportPath,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { moveTaskDirect } from '../core/task-master-core.js';
|
import { moveTaskDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the moveTask tool with the MCP server
|
* Register the moveTask tool with the MCP server
|
||||||
@@ -37,15 +36,10 @@ export function registerMoveTaskTool(server) {
|
|||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe(
|
||||||
'Root directory of the project (typically derived from session)'
|
'Root directory of the project (typically derived from session)'
|
||||||
),
|
)
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
// Find tasks.json path if not provided
|
// Find tasks.json path if not provided
|
||||||
let tasksJsonPath = args.file;
|
let tasksJsonPath = args.file;
|
||||||
|
|
||||||
@@ -85,8 +79,7 @@ export function registerMoveTaskTool(server) {
|
|||||||
sourceId: fromId,
|
sourceId: fromId,
|
||||||
destinationId: toId,
|
destinationId: toId,
|
||||||
tasksJsonPath,
|
tasksJsonPath,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
@@ -122,8 +115,7 @@ export function registerMoveTaskTool(server) {
|
|||||||
sourceId: args.from,
|
sourceId: args.from,
|
||||||
destinationId: args.to,
|
destinationId: args.to,
|
||||||
tasksJsonPath,
|
tasksJsonPath,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
resolveTasksPath,
|
resolveTasksPath,
|
||||||
resolveComplexityReportPath
|
resolveComplexityReportPath
|
||||||
} from '../core/utils/path-utils.js';
|
} from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the nextTask tool with the MCP server
|
* Register the nextTask tool with the MCP server
|
||||||
@@ -35,16 +34,11 @@ export function registerNextTaskTool(server) {
|
|||||||
),
|
),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
log.info(`Finding next task with args: ${JSON.stringify(args)}`);
|
log.info(`Finding next task with args: ${JSON.stringify(args)}`);
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// Resolve the path to tasks.json using new path utilities
|
// Resolve the path to tasks.json using new path utilities
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
@@ -60,10 +54,7 @@ export function registerNextTaskTool(server) {
|
|||||||
// Resolve the path to complexity report (optional)
|
// Resolve the path to complexity report (optional)
|
||||||
let complexityReportPath;
|
let complexityReportPath;
|
||||||
try {
|
try {
|
||||||
complexityReportPath = resolveComplexityReportPath(
|
complexityReportPath = resolveComplexityReportPath(args, session);
|
||||||
{ ...args, tag: resolvedTag },
|
|
||||||
session
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error finding complexity report: ${error.message}`);
|
log.error(`Error finding complexity report: ${error.message}`);
|
||||||
// This is optional, so we don't fail the operation
|
// This is optional, so we don't fail the operation
|
||||||
@@ -74,8 +65,7 @@ export function registerNextTaskTool(server) {
|
|||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
reportPath: complexityReportPath,
|
reportPath: complexityReportPath,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
TASKMASTER_DOCS_DIR,
|
TASKMASTER_DOCS_DIR,
|
||||||
TASKMASTER_TASKS_FILE
|
TASKMASTER_TASKS_FILE
|
||||||
} from '../../../src/constants/paths.js';
|
} from '../../../src/constants/paths.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the parse_prd tool
|
* Register the parse_prd tool
|
||||||
@@ -25,7 +24,6 @@ export function registerParsePRDTool(server) {
|
|||||||
server.addTool({
|
server.addTool({
|
||||||
name: 'parse_prd',
|
name: 'parse_prd',
|
||||||
description: `Parse a Product Requirements Document (PRD) text file to automatically generate initial tasks. Reinitializing the project is not necessary to run this tool. It is recommended to run parse-prd after initializing the project and creating/importing a prd.txt file in the project root's ${TASKMASTER_DOCS_DIR} directory.`,
|
description: `Parse a Product Requirements Document (PRD) text file to automatically generate initial tasks. Reinitializing the project is not necessary to run this tool. It is recommended to run parse-prd after initializing the project and creating/importing a prd.txt file in the project root's ${TASKMASTER_DOCS_DIR} directory.`,
|
||||||
|
|
||||||
parameters: z.object({
|
parameters: z.object({
|
||||||
input: z
|
input: z
|
||||||
.string()
|
.string()
|
||||||
@@ -35,7 +33,6 @@ export function registerParsePRDTool(server) {
|
|||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.'),
|
||||||
tag: z.string().optional().describe('Tag context to operate on'),
|
|
||||||
output: z
|
output: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -66,18 +63,7 @@ export function registerParsePRDTool(server) {
|
|||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
const result = await parsePRDDirect(args, log, { session });
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
const result = await parsePRDDirect(
|
|
||||||
{
|
|
||||||
...args,
|
|
||||||
tag: resolvedTag
|
|
||||||
},
|
|
||||||
log,
|
|
||||||
{ session }
|
|
||||||
);
|
|
||||||
return handleApiResult(
|
return handleApiResult(
|
||||||
result,
|
result,
|
||||||
log,
|
log,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { removeDependencyDirect } from '../core/task-master-core.js';
|
import { removeDependencyDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the removeDependency tool with the MCP server
|
* Register the removeDependency tool with the MCP server
|
||||||
@@ -32,15 +31,10 @@ export function registerRemoveDependencyTool(server) {
|
|||||||
),
|
),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
log.info(
|
log.info(
|
||||||
`Removing dependency for task ${args.id} from ${args.dependsOn} with args: ${JSON.stringify(args)}`
|
`Removing dependency for task ${args.id} from ${args.dependsOn} with args: ${JSON.stringify(args)}`
|
||||||
);
|
);
|
||||||
@@ -63,9 +57,7 @@ export function registerRemoveDependencyTool(server) {
|
|||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
id: args.id,
|
id: args.id,
|
||||||
dependsOn: args.dependsOn,
|
dependsOn: args.dependsOn
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log
|
log
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { removeSubtaskDirect } from '../core/task-master-core.js';
|
import { removeSubtaskDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the removeSubtask tool with the MCP server
|
* Register the removeSubtask tool with the MCP server
|
||||||
@@ -45,15 +44,10 @@ export function registerRemoveSubtaskTool(server) {
|
|||||||
.describe('Skip regenerating task files'),
|
.describe('Skip regenerating task files'),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
log.info(`Removing subtask with args: ${JSON.stringify(args)}`);
|
log.info(`Removing subtask with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
@@ -76,8 +70,7 @@ export function registerRemoveSubtaskTool(server) {
|
|||||||
id: args.id,
|
id: args.id,
|
||||||
convert: args.convert,
|
convert: args.convert,
|
||||||
skipGenerate: args.skipGenerate,
|
skipGenerate: args.skipGenerate,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { removeTaskDirect } from '../core/task-master-core.js';
|
import { removeTaskDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the remove-task tool with the MCP server
|
* Register the remove-task tool with the MCP server
|
||||||
@@ -46,11 +45,6 @@ export function registerRemoveTaskTool(server) {
|
|||||||
try {
|
try {
|
||||||
log.info(`Removing task(s) with ID(s): ${args.id}`);
|
log.info(`Removing task(s) with ID(s): ${args.id}`);
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -72,7 +66,7 @@ export function registerRemoveTaskTool(server) {
|
|||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath,
|
||||||
id: args.id,
|
id: args.id,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag
|
tag: args.tag
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
withNormalizedProjectRoot
|
withNormalizedProjectRoot
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { researchDirect } from '../core/task-master-core.js';
|
import { researchDirect } from '../core/task-master-core.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the research tool with the MCP server
|
* Register the research tool with the MCP server
|
||||||
@@ -20,7 +19,6 @@ export function registerResearchTool(server) {
|
|||||||
server.addTool({
|
server.addTool({
|
||||||
name: 'research',
|
name: 'research',
|
||||||
description: 'Perform AI-powered research queries with project context',
|
description: 'Perform AI-powered research queries with project context',
|
||||||
|
|
||||||
parameters: z.object({
|
parameters: z.object({
|
||||||
query: z.string().describe('Research query/prompt (required)'),
|
query: z.string().describe('Research query/prompt (required)'),
|
||||||
taskIds: z
|
taskIds: z
|
||||||
@@ -63,15 +61,10 @@ export function registerResearchTool(server) {
|
|||||||
),
|
),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
log.info(
|
log.info(
|
||||||
`Starting research with query: "${args.query.substring(0, 100)}${args.query.length > 100 ? '...' : ''}"`
|
`Starting research with query: "${args.query.substring(0, 100)}${args.query.length > 100 ? '...' : ''}"`
|
||||||
);
|
);
|
||||||
@@ -87,8 +80,7 @@ export function registerResearchTool(server) {
|
|||||||
detailLevel: args.detailLevel || 'medium',
|
detailLevel: args.detailLevel || 'medium',
|
||||||
saveTo: args.saveTo,
|
saveTo: args.saveTo,
|
||||||
saveToFile: args.saveToFile || false,
|
saveToFile: args.saveToFile || false,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
findComplexityReportPath
|
findComplexityReportPath
|
||||||
} from '../core/utils/path-utils.js';
|
} from '../core/utils/path-utils.js';
|
||||||
import { TASK_STATUS_OPTIONS } from '../../../src/constants/task-status.js';
|
import { TASK_STATUS_OPTIONS } from '../../../src/constants/task-status.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the setTaskStatus tool with the MCP server
|
* Register the setTaskStatus tool with the MCP server
|
||||||
@@ -53,15 +52,8 @@ export function registerSetTaskStatusTool(server) {
|
|||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
log.info(
|
log.info(`Setting status of task(s) ${args.id} to: ${args.status}`);
|
||||||
`Setting status of task(s) ${args.id} to: ${args.status} ${
|
|
||||||
args.tag ? `in tag: ${args.tag}` : 'in current tag'
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
try {
|
try {
|
||||||
@@ -81,8 +73,7 @@ export function registerSetTaskStatusTool(server) {
|
|||||||
complexityReportPath = findComplexityReportPath(
|
complexityReportPath = findComplexityReportPath(
|
||||||
{
|
{
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
complexityReport: args.complexityReport,
|
complexityReport: args.complexityReport
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log
|
log
|
||||||
);
|
);
|
||||||
@@ -97,7 +88,7 @@ export function registerSetTaskStatusTool(server) {
|
|||||||
status: args.status,
|
status: args.status,
|
||||||
complexityReportPath,
|
complexityReportPath,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot,
|
||||||
tag: resolvedTag
|
tag: args.tag
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { updateSubtaskByIdDirect } from '../core/task-master-core.js';
|
import { updateSubtaskByIdDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the update-subtask tool with the MCP server
|
* Register the update-subtask tool with the MCP server
|
||||||
@@ -36,17 +35,11 @@ export function registerUpdateSubtaskTool(server) {
|
|||||||
file: z.string().optional().describe('Absolute path to the tasks file'),
|
file: z.string().optional().describe('Absolute path to the tasks file'),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
const toolName = 'update_subtask';
|
const toolName = 'update_subtask';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
log.info(`Updating subtask with args: ${JSON.stringify(args)}`);
|
log.info(`Updating subtask with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
let tasksJsonPath;
|
let tasksJsonPath;
|
||||||
@@ -68,8 +61,7 @@ export function registerUpdateSubtaskTool(server) {
|
|||||||
id: args.id,
|
id: args.id,
|
||||||
prompt: args.prompt,
|
prompt: args.prompt,
|
||||||
research: args.research,
|
research: args.research,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { updateTaskByIdDirect } from '../core/task-master-core.js';
|
import { updateTaskByIdDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the update-task tool with the MCP server
|
* Register the update-task tool with the MCP server
|
||||||
@@ -44,16 +43,11 @@ export function registerUpdateTaskTool(server) {
|
|||||||
file: z.string().optional().describe('Absolute path to the tasks file'),
|
file: z.string().optional().describe('Absolute path to the tasks file'),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
const toolName = 'update_task';
|
const toolName = 'update_task';
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
log.info(
|
log.info(
|
||||||
`Executing ${toolName} tool with args: ${JSON.stringify(args)}`
|
`Executing ${toolName} tool with args: ${JSON.stringify(args)}`
|
||||||
);
|
);
|
||||||
@@ -80,8 +74,7 @@ export function registerUpdateTaskTool(server) {
|
|||||||
prompt: args.prompt,
|
prompt: args.prompt,
|
||||||
research: args.research,
|
research: args.research,
|
||||||
append: args.append,
|
append: args.append,
|
||||||
projectRoot: args.projectRoot,
|
projectRoot: args.projectRoot
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { updateTasksDirect } from '../core/task-master-core.js';
|
import { updateTasksDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the update tool with the MCP server
|
* Register the update tool with the MCP server
|
||||||
@@ -51,11 +50,6 @@ export function registerUpdateTool(server) {
|
|||||||
const toolName = 'update';
|
const toolName = 'update';
|
||||||
const { from, prompt, research, file, projectRoot, tag } = args;
|
const { from, prompt, research, file, projectRoot, tag } = args;
|
||||||
|
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.info(
|
log.info(
|
||||||
`Executing ${toolName} tool with normalized root: ${projectRoot}`
|
`Executing ${toolName} tool with normalized root: ${projectRoot}`
|
||||||
@@ -79,7 +73,7 @@ export function registerUpdateTool(server) {
|
|||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
research: research,
|
research: research,
|
||||||
projectRoot: projectRoot,
|
projectRoot: projectRoot,
|
||||||
tag: resolvedTag
|
tag: tag
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{ session }
|
{ session }
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { validateDependenciesDirect } from '../core/task-master-core.js';
|
import { validateDependenciesDirect } from '../core/task-master-core.js';
|
||||||
import { findTasksPath } from '../core/utils/path-utils.js';
|
import { findTasksPath } from '../core/utils/path-utils.js';
|
||||||
import { resolveTag } from '../../../scripts/modules/utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the validateDependencies tool with the MCP server
|
* Register the validateDependencies tool with the MCP server
|
||||||
@@ -26,15 +25,10 @@ export function registerValidateDependenciesTool(server) {
|
|||||||
file: z.string().optional().describe('Absolute path to the tasks file'),
|
file: z.string().optional().describe('Absolute path to the tasks file'),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
.describe('The directory of the project. Must be an absolute path.'),
|
.describe('The directory of the project. Must be an absolute path.')
|
||||||
tag: z.string().optional().describe('Tag context to operate on')
|
|
||||||
}),
|
}),
|
||||||
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
execute: withNormalizedProjectRoot(async (args, { log, session }) => {
|
||||||
try {
|
try {
|
||||||
const resolvedTag = resolveTag({
|
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: args.tag
|
|
||||||
});
|
|
||||||
log.info(`Validating dependencies with args: ${JSON.stringify(args)}`);
|
log.info(`Validating dependencies with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
|
||||||
@@ -53,9 +47,7 @@ export function registerValidateDependenciesTool(server) {
|
|||||||
|
|
||||||
const result = await validateDependenciesDirect(
|
const result = await validateDependenciesDirect(
|
||||||
{
|
{
|
||||||
tasksJsonPath: tasksJsonPath,
|
tasksJsonPath: tasksJsonPath
|
||||||
projectRoot: args.projectRoot,
|
|
||||||
tag: resolvedTag
|
|
||||||
},
|
},
|
||||||
log
|
log
|
||||||
);
|
);
|
||||||
|
|||||||
37
package-lock.json
generated
37
package-lock.json
generated
@@ -1,17 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "0.20.0",
|
"version": "0.19.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "0.20.0",
|
"version": "0.19.0",
|
||||||
"license": "MIT WITH Commons-Clause",
|
"license": "MIT WITH Commons-Clause",
|
||||||
"workspaces": [
|
|
||||||
"apps/*",
|
|
||||||
"."
|
|
||||||
],
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/amazon-bedrock": "^2.2.9",
|
"@ai-sdk/amazon-bedrock": "^2.2.9",
|
||||||
"@ai-sdk/anthropic": "^1.2.10",
|
"@ai-sdk/anthropic": "^1.2.10",
|
||||||
@@ -84,13 +80,6 @@
|
|||||||
"ai-sdk-provider-gemini-cli": "^0.0.4"
|
"ai-sdk-provider-gemini-cli": "^0.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"apps/extension": {
|
|
||||||
"version": "0.20.0",
|
|
||||||
"license": "ISC",
|
|
||||||
"devDependencies": {
|
|
||||||
"typescript": "^5.8.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@ai-sdk/amazon-bedrock": {
|
"node_modules/@ai-sdk/amazon-bedrock": {
|
||||||
"version": "2.2.10",
|
"version": "2.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/@ai-sdk/amazon-bedrock/-/amazon-bedrock-2.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/@ai-sdk/amazon-bedrock/-/amazon-bedrock-2.2.10.tgz",
|
||||||
@@ -7351,10 +7340,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/extension": {
|
|
||||||
"resolved": "apps/extension",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/external-editor": {
|
"node_modules/external-editor": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||||
@@ -12992,10 +12977,6 @@
|
|||||||
"react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/task-master-ai": {
|
|
||||||
"resolved": "",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/term-size": {
|
"node_modules/term-size": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
|
||||||
@@ -13204,20 +13185,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
|
||||||
"version": "5.8.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
|
||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"tsc": "bin/tsc",
|
|
||||||
"tsserver": "bin/tsserver"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.17"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/uint8array-extras": {
|
"node_modules/uint8array-extras": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.4.0.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "0.21.0",
|
"version": "0.20.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,6 @@
|
|||||||
"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": [
|
|
||||||
"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",
|
||||||
|
|||||||
@@ -8,48 +8,47 @@
|
|||||||
|
|
||||||
// --- Core Dependencies ---
|
// --- Core Dependencies ---
|
||||||
import {
|
import {
|
||||||
MODEL_MAP,
|
|
||||||
getAzureBaseURL,
|
|
||||||
getBaseUrlForRole,
|
|
||||||
getBedrockBaseURL,
|
|
||||||
getDebugFlag,
|
|
||||||
getFallbackModelId,
|
|
||||||
getFallbackProvider,
|
|
||||||
getMainModelId,
|
|
||||||
getMainProvider,
|
getMainProvider,
|
||||||
getOllamaBaseURL,
|
getMainModelId,
|
||||||
getParametersForRole,
|
|
||||||
getResearchModelId,
|
|
||||||
getResearchProvider,
|
getResearchProvider,
|
||||||
|
getResearchModelId,
|
||||||
|
getFallbackProvider,
|
||||||
|
getFallbackModelId,
|
||||||
|
getParametersForRole,
|
||||||
getResponseLanguage,
|
getResponseLanguage,
|
||||||
getUserId,
|
getUserId,
|
||||||
getVertexLocation,
|
MODEL_MAP,
|
||||||
getVertexProjectId,
|
getDebugFlag,
|
||||||
|
getBaseUrlForRole,
|
||||||
isApiKeySet,
|
isApiKeySet,
|
||||||
|
getOllamaBaseURL,
|
||||||
|
getAzureBaseURL,
|
||||||
|
getBedrockBaseURL,
|
||||||
|
getVertexProjectId,
|
||||||
|
getVertexLocation,
|
||||||
providersWithoutApiKeys
|
providersWithoutApiKeys
|
||||||
} from './config-manager.js';
|
} from './config-manager.js';
|
||||||
import {
|
import {
|
||||||
findProjectRoot,
|
|
||||||
getCurrentTag,
|
|
||||||
log,
|
log,
|
||||||
resolveEnvVariable
|
findProjectRoot,
|
||||||
|
resolveEnvVariable,
|
||||||
|
getCurrentTag
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
|
|
||||||
// Import provider classes
|
// Import provider classes
|
||||||
import {
|
import {
|
||||||
AnthropicAIProvider,
|
AnthropicAIProvider,
|
||||||
AzureProvider,
|
|
||||||
BedrockAIProvider,
|
|
||||||
ClaudeCodeProvider,
|
|
||||||
GeminiCliProvider,
|
|
||||||
GoogleAIProvider,
|
|
||||||
GroqProvider,
|
|
||||||
OllamaAIProvider,
|
|
||||||
OpenAIProvider,
|
|
||||||
OpenRouterAIProvider,
|
|
||||||
PerplexityAIProvider,
|
PerplexityAIProvider,
|
||||||
|
GoogleAIProvider,
|
||||||
|
OpenAIProvider,
|
||||||
|
XAIProvider,
|
||||||
|
OpenRouterAIProvider,
|
||||||
|
OllamaAIProvider,
|
||||||
|
BedrockAIProvider,
|
||||||
|
AzureProvider,
|
||||||
VertexAIProvider,
|
VertexAIProvider,
|
||||||
XAIProvider
|
ClaudeCodeProvider,
|
||||||
|
GeminiCliProvider
|
||||||
} from '../../src/ai-providers/index.js';
|
} from '../../src/ai-providers/index.js';
|
||||||
|
|
||||||
// Import the provider registry
|
// Import the provider registry
|
||||||
@@ -62,7 +61,6 @@ const PROVIDERS = {
|
|||||||
google: new GoogleAIProvider(),
|
google: new GoogleAIProvider(),
|
||||||
openai: new OpenAIProvider(),
|
openai: new OpenAIProvider(),
|
||||||
xai: new XAIProvider(),
|
xai: new XAIProvider(),
|
||||||
groq: new GroqProvider(),
|
|
||||||
openrouter: new OpenRouterAIProvider(),
|
openrouter: new OpenRouterAIProvider(),
|
||||||
ollama: new OllamaAIProvider(),
|
ollama: new OllamaAIProvider(),
|
||||||
bedrock: new BedrockAIProvider(),
|
bedrock: new BedrockAIProvider(),
|
||||||
|
|||||||
@@ -826,8 +826,7 @@ function registerCommands(programInstance) {
|
|||||||
let taskMaster;
|
let taskMaster;
|
||||||
try {
|
try {
|
||||||
const initOptions = {
|
const initOptions = {
|
||||||
prdPath: file || options.input || true,
|
prdPath: file || options.input || true
|
||||||
tag: options.tag
|
|
||||||
};
|
};
|
||||||
// Only include tasksPath if output is explicitly specified
|
// Only include tasksPath if output is explicitly specified
|
||||||
if (options.output) {
|
if (options.output) {
|
||||||
@@ -853,7 +852,8 @@ function registerCommands(programInstance) {
|
|||||||
const useAppend = append;
|
const useAppend = append;
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -966,8 +966,7 @@ function registerCommands(programInstance) {
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fromId = parseInt(options.from, 10); // Validation happens here
|
const fromId = parseInt(options.from, 10); // Validation happens here
|
||||||
@@ -977,7 +976,8 @@ function registerCommands(programInstance) {
|
|||||||
const tasksPath = taskMaster.getTasksPath();
|
const tasksPath = taskMaster.getTasksPath();
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -1066,13 +1066,13 @@ function registerCommands(programInstance) {
|
|||||||
try {
|
try {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
const tasksPath = taskMaster.getTasksPath();
|
const tasksPath = taskMaster.getTasksPath();
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -1238,13 +1238,13 @@ function registerCommands(programInstance) {
|
|||||||
try {
|
try {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
const tasksPath = taskMaster.getTasksPath();
|
const tasksPath = taskMaster.getTasksPath();
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -1404,12 +1404,11 @@ function registerCommands(programInstance) {
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const outputDir = options.output;
|
const outputDir = options.output;
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag = options.tag;
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
chalk.blue(`Generating task files from: ${taskMaster.getTasksPath()}`)
|
chalk.blue(`Generating task files from: ${taskMaster.getTasksPath()}`)
|
||||||
@@ -1445,12 +1444,12 @@ function registerCommands(programInstance) {
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const taskId = options.id;
|
const taskId = options.id;
|
||||||
const status = options.status;
|
const status = options.status;
|
||||||
|
const tag = options.tag;
|
||||||
|
|
||||||
if (!taskId || !status) {
|
if (!taskId || !status) {
|
||||||
console.error(chalk.red('Error: Both --id and --status are required'));
|
console.error(chalk.red('Error: Both --id and --status are required'));
|
||||||
@@ -1466,9 +1465,11 @@ function registerCommands(programInstance) {
|
|||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const tag = taskMaster.getCurrentTag();
|
|
||||||
|
|
||||||
displayCurrentTagIndicator(tag);
|
// Resolve tag using standard pattern and show current tag context
|
||||||
|
const resolvedTag =
|
||||||
|
tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
displayCurrentTagIndicator(resolvedTag);
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
chalk.blue(`Setting status of task(s) ${taskId} to: ${status}`)
|
chalk.blue(`Setting status of task(s) ${taskId} to: ${status}`)
|
||||||
@@ -1500,8 +1501,7 @@ function registerCommands(programInstance) {
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const initOptions = {
|
const initOptions = {
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only pass complexityReportPath if user provided a custom path
|
// Only pass complexityReportPath if user provided a custom path
|
||||||
@@ -1513,7 +1513,9 @@ function registerCommands(programInstance) {
|
|||||||
|
|
||||||
const statusFilter = options.status;
|
const statusFilter = options.status;
|
||||||
const withSubtasks = options.withSubtasks || false;
|
const withSubtasks = options.withSubtasks || false;
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
|
|
||||||
@@ -1533,7 +1535,8 @@ function registerCommands(programInstance) {
|
|||||||
taskMaster.getComplexityReportPath(),
|
taskMaster.getComplexityReportPath(),
|
||||||
withSubtasks,
|
withSubtasks,
|
||||||
'text',
|
'text',
|
||||||
{ projectRoot: taskMaster.getProjectRoot(), tag }
|
tag,
|
||||||
|
{ projectRoot: taskMaster.getProjectRoot() }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1562,29 +1565,18 @@ function registerCommands(programInstance) {
|
|||||||
'Path to the tasks file (relative to project root)',
|
'Path to the tasks file (relative to project root)',
|
||||||
TASKMASTER_TASKS_FILE // Allow file override
|
TASKMASTER_TASKS_FILE // Allow file override
|
||||||
) // Allow file override
|
) // Allow file override
|
||||||
.option(
|
|
||||||
'-cr, --complexity-report <file>',
|
|
||||||
'Path to the report file',
|
|
||||||
COMPLEXITY_REPORT_FILE
|
|
||||||
)
|
|
||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const initOptions = {
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
});
|
||||||
};
|
const tag = options.tag;
|
||||||
|
|
||||||
if (options.complexityReport) {
|
|
||||||
initOptions.complexityReportPath = options.complexityReport;
|
|
||||||
}
|
|
||||||
|
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
|
||||||
|
|
||||||
const tag = taskMaster.getCurrentTag();
|
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(
|
||||||
|
tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master'
|
||||||
|
);
|
||||||
|
|
||||||
if (options.all) {
|
if (options.all) {
|
||||||
// --- Handle expand --all ---
|
// --- Handle expand --all ---
|
||||||
@@ -1597,11 +1589,7 @@ function registerCommands(programInstance) {
|
|||||||
options.research, // Pass research flag
|
options.research, // Pass research flag
|
||||||
options.prompt, // Pass additional context
|
options.prompt, // Pass additional context
|
||||||
options.force, // Pass force flag
|
options.force, // Pass force flag
|
||||||
{
|
{ projectRoot: taskMaster.getProjectRoot(), tag } // Pass context with projectRoot and tag
|
||||||
projectRoot: taskMaster.getProjectRoot(),
|
|
||||||
tag,
|
|
||||||
complexityReportPath: taskMaster.getComplexityReportPath()
|
|
||||||
} // Pass context with projectRoot and tag
|
|
||||||
// outputFormat defaults to 'text' in expandAllTasks for CLI
|
// outputFormat defaults to 'text' in expandAllTasks for CLI
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1628,11 +1616,7 @@ function registerCommands(programInstance) {
|
|||||||
options.num,
|
options.num,
|
||||||
options.research,
|
options.research,
|
||||||
options.prompt,
|
options.prompt,
|
||||||
{
|
{ projectRoot: taskMaster.getProjectRoot(), tag }, // Pass context with projectRoot and tag
|
||||||
projectRoot: taskMaster.getProjectRoot(),
|
|
||||||
tag,
|
|
||||||
complexityReportPath: taskMaster.getComplexityReportPath()
|
|
||||||
}, // Pass context with projectRoot and tag
|
|
||||||
options.force // Pass the force flag down
|
options.force // Pass the force flag down
|
||||||
);
|
);
|
||||||
// expandTask logs its own success/failure for single task
|
// expandTask logs its own success/failure for single task
|
||||||
@@ -1685,28 +1669,34 @@ function registerCommands(programInstance) {
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const initOptions = {
|
const initOptions = {
|
||||||
tasksPath: options.file || true, // Tasks file is required to analyze
|
tasksPath: options.file || true // Tasks file is required to analyze
|
||||||
tag: options.tag
|
|
||||||
};
|
};
|
||||||
// Only include complexityReportPath if output is explicitly specified
|
// Only include complexityReportPath if output is explicitly specified
|
||||||
if (options.output) {
|
if (options.output) {
|
||||||
initOptions.complexityReportPath = options.output;
|
initOptions.complexityReportPath = options.output;
|
||||||
}
|
}
|
||||||
|
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
const taskMaster = initTaskMaster(initOptions);
|
||||||
|
|
||||||
|
const tag = options.tag;
|
||||||
const modelOverride = options.model;
|
const modelOverride = options.model;
|
||||||
const thresholdScore = parseFloat(options.threshold);
|
const thresholdScore = parseFloat(options.threshold);
|
||||||
const useResearch = options.research || false;
|
const useResearch = options.research || false;
|
||||||
|
|
||||||
// Use the provided tag, or the current active tag, or default to 'master'
|
// Use the provided tag, or the current active tag, or default to 'master'
|
||||||
const targetTag = taskMaster.getCurrentTag();
|
const targetTag =
|
||||||
|
tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(targetTag);
|
displayCurrentTagIndicator(targetTag);
|
||||||
|
|
||||||
// Use user's explicit output path if provided, otherwise use tag-aware default
|
// Tag-aware output file naming: master -> task-complexity-report.json, other tags -> task-complexity-report_tagname.json
|
||||||
const outputPath = taskMaster.getComplexityReportPath();
|
const baseOutputPath =
|
||||||
|
taskMaster.getComplexityReportPath() ||
|
||||||
|
path.join(taskMaster.getProjectRoot(), COMPLEXITY_REPORT_FILE);
|
||||||
|
const outputPath =
|
||||||
|
options.output === COMPLEXITY_REPORT_FILE && targetTag !== 'master'
|
||||||
|
? baseOutputPath.replace('.json', `_${targetTag}.json`)
|
||||||
|
: options.output || baseOutputPath;
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
chalk.blue(
|
chalk.blue(
|
||||||
@@ -1787,12 +1777,9 @@ function registerCommands(programInstance) {
|
|||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (prompt, options) => {
|
.action(async (prompt, options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const initOptions = {
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
|
||||||
|
|
||||||
// Parameter validation
|
// Parameter validation
|
||||||
if (!prompt || typeof prompt !== 'string' || prompt.trim().length === 0) {
|
if (!prompt || typeof prompt !== 'string' || prompt.trim().length === 0) {
|
||||||
@@ -1892,7 +1879,8 @@ function registerCommands(programInstance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -2125,17 +2113,17 @@ ${result.result}
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const taskIds = options.id;
|
const taskIds = options.id;
|
||||||
const all = options.all;
|
const all = options.all;
|
||||||
|
const tag = options.tag;
|
||||||
|
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const tag = taskMaster.getCurrentTag();
|
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(
|
||||||
|
tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master'
|
||||||
|
);
|
||||||
|
|
||||||
if (!taskIds && !all) {
|
if (!taskIds && !all) {
|
||||||
console.error(
|
console.error(
|
||||||
@@ -2231,16 +2219,15 @@ ${result.result}
|
|||||||
// Correctly determine projectRoot
|
// Correctly determine projectRoot
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const projectRoot = taskMaster.getProjectRoot();
|
const projectRoot = taskMaster.getProjectRoot();
|
||||||
|
|
||||||
const tag = taskMaster.getCurrentTag();
|
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master'
|
||||||
|
);
|
||||||
|
|
||||||
let manualTaskData = null;
|
let manualTaskData = null;
|
||||||
if (isManualCreation) {
|
if (isManualCreation) {
|
||||||
@@ -2276,7 +2263,7 @@ ${result.result}
|
|||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
projectRoot,
|
projectRoot,
|
||||||
tag,
|
tag: options.tag,
|
||||||
commandName: 'add-task',
|
commandName: 'add-task',
|
||||||
outputType: 'cli'
|
outputType: 'cli'
|
||||||
};
|
};
|
||||||
@@ -2322,36 +2309,22 @@ ${result.result}
|
|||||||
)
|
)
|
||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const initOptions = {
|
const tag = options.tag;
|
||||||
tasksPath: options.file || true,
|
|
||||||
tag: options.tag
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.report && options.report !== COMPLEXITY_REPORT_FILE) {
|
|
||||||
initOptions.complexityReportPath = options.report;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag,
|
|
||||||
complexityReportPath: options.report || false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const tag = taskMaster.getCurrentTag();
|
|
||||||
|
|
||||||
const context = {
|
|
||||||
projectRoot: taskMaster.getProjectRoot(),
|
|
||||||
tag
|
|
||||||
};
|
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(
|
||||||
|
tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master'
|
||||||
|
);
|
||||||
|
|
||||||
await displayNextTask(
|
await displayNextTask(
|
||||||
taskMaster.getTasksPath(),
|
taskMaster.getTasksPath(),
|
||||||
taskMaster.getComplexityReportPath(),
|
taskMaster.getComplexityReportPath(),
|
||||||
context
|
{ projectRoot: taskMaster.getProjectRoot(), tag }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2380,21 +2353,19 @@ ${result.result}
|
|||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (taskId, options) => {
|
.action(async (taskId, options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const initOptions = {
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true
|
tasksPath: options.file || true,
|
||||||
};
|
complexityReportPath: options.report || false
|
||||||
// Only pass complexityReportPath if user provided a custom path
|
});
|
||||||
if (options.report && options.report !== COMPLEXITY_REPORT_FILE) {
|
|
||||||
initOptions.complexityReportPath = options.report;
|
|
||||||
}
|
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
|
||||||
|
|
||||||
const idArg = taskId || options.id;
|
const idArg = taskId || options.id;
|
||||||
const statusFilter = options.status;
|
const statusFilter = options.status;
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag = options.tag;
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(
|
||||||
|
tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master'
|
||||||
|
);
|
||||||
|
|
||||||
if (!idArg) {
|
if (!idArg) {
|
||||||
console.error(chalk.red('Error: Please provide a task ID'));
|
console.error(chalk.red('Error: Please provide a task ID'));
|
||||||
@@ -2423,7 +2394,8 @@ ${result.result}
|
|||||||
taskIds[0],
|
taskIds[0],
|
||||||
taskMaster.getComplexityReportPath(),
|
taskMaster.getComplexityReportPath(),
|
||||||
statusFilter,
|
statusFilter,
|
||||||
{ projectRoot: taskMaster.getProjectRoot(), tag }
|
tag,
|
||||||
|
{ projectRoot: taskMaster.getProjectRoot() }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2441,19 +2413,17 @@ ${result.result}
|
|||||||
)
|
)
|
||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const initOptions = {
|
|
||||||
tasksPath: options.file || true,
|
|
||||||
tag: options.tag
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
const taskMaster = initTaskMaster({
|
||||||
|
tasksPath: options.file || true
|
||||||
|
});
|
||||||
|
|
||||||
const taskId = options.id;
|
const taskId = options.id;
|
||||||
const dependencyId = options.dependsOn;
|
const dependencyId = options.dependsOn;
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -2498,19 +2468,17 @@ ${result.result}
|
|||||||
)
|
)
|
||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const initOptions = {
|
|
||||||
tasksPath: options.file || true,
|
|
||||||
tag: options.tag
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
const taskMaster = initTaskMaster({
|
||||||
|
tasksPath: options.file || true
|
||||||
|
});
|
||||||
|
|
||||||
const taskId = options.id;
|
const taskId = options.id;
|
||||||
const dependencyId = options.dependsOn;
|
const dependencyId = options.dependsOn;
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -2555,16 +2523,14 @@ ${result.result}
|
|||||||
)
|
)
|
||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const initOptions = {
|
|
||||||
tasksPath: options.file || true,
|
|
||||||
tag: options.tag
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
const taskMaster = initTaskMaster({
|
||||||
|
tasksPath: options.file || true
|
||||||
|
});
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -2585,16 +2551,14 @@ ${result.result}
|
|||||||
)
|
)
|
||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const initOptions = {
|
|
||||||
tasksPath: options.file || true,
|
|
||||||
tag: options.tag
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
const taskMaster = initTaskMaster({
|
||||||
|
tasksPath: options.file || true
|
||||||
|
});
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -2615,21 +2579,26 @@ ${result.result}
|
|||||||
)
|
)
|
||||||
.option('--tag <tag>', 'Specify tag context for task operations')
|
.option('--tag <tag>', 'Specify tag context for task operations')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const initOptions = {
|
|
||||||
tag: options.tag
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.file && options.file !== COMPLEXITY_REPORT_FILE) {
|
|
||||||
initOptions.complexityReportPath = options.file;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster(initOptions);
|
const taskMaster = initTaskMaster({
|
||||||
|
complexityReportPath: options.file || true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use the provided tag, or the current active tag, or default to 'master'
|
||||||
|
const targetTag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(taskMaster.getCurrentTag());
|
displayCurrentTagIndicator(targetTag);
|
||||||
|
|
||||||
await displayComplexityReport(taskMaster.getComplexityReportPath());
|
// Tag-aware report file naming: master -> task-complexity-report.json, other tags -> task-complexity-report_tagname.json
|
||||||
|
const baseReportPath = taskMaster.getComplexityReportPath();
|
||||||
|
const reportPath =
|
||||||
|
options.file === COMPLEXITY_REPORT_FILE && targetTag !== 'master'
|
||||||
|
? baseReportPath.replace('.json', `_${targetTag}.json`)
|
||||||
|
: baseReportPath;
|
||||||
|
|
||||||
|
await displayComplexityReport(reportPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
// add-subtask command
|
// add-subtask command
|
||||||
@@ -2659,8 +2628,7 @@ ${result.result}
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const parentId = options.parent;
|
const parentId = options.parent;
|
||||||
@@ -2668,7 +2636,8 @@ ${result.result}
|
|||||||
const generateFiles = !options.skipGenerate;
|
const generateFiles = !options.skipGenerate;
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -2843,14 +2812,13 @@ ${result.result}
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const subtaskIds = options.id;
|
const subtaskIds = options.id;
|
||||||
const convertToTask = options.convert || false;
|
const convertToTask = options.convert || false;
|
||||||
const generateFiles = !options.skipGenerate;
|
const generateFiles = !options.skipGenerate;
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag = options.tag;
|
||||||
|
|
||||||
if (!subtaskIds) {
|
if (!subtaskIds) {
|
||||||
console.error(
|
console.error(
|
||||||
@@ -3145,14 +3113,14 @@ ${result.result}
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const taskIdsString = options.id;
|
const taskIdsString = options.id;
|
||||||
|
|
||||||
// Resolve tag using standard pattern
|
// Resolve tag using standard pattern
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag =
|
||||||
|
options.tag || getCurrentTag(taskMaster.getProjectRoot()) || 'master';
|
||||||
|
|
||||||
// Show current tag context
|
// Show current tag context
|
||||||
displayCurrentTagIndicator(tag);
|
displayCurrentTagIndicator(tag);
|
||||||
@@ -3727,7 +3695,10 @@ Examples:
|
|||||||
const taskMaster = initTaskMaster({});
|
const taskMaster = initTaskMaster({});
|
||||||
const projectRoot = taskMaster.getProjectRoot(); // Find project root for context
|
const projectRoot = taskMaster.getProjectRoot(); // Find project root for context
|
||||||
const { response, setup } = options;
|
const { response, setup } = options;
|
||||||
let responseLanguage = response !== undefined ? response : 'English';
|
console.log(
|
||||||
|
chalk.blue('Response language set to:', JSON.stringify(options))
|
||||||
|
);
|
||||||
|
let responseLanguage = response || 'English';
|
||||||
if (setup) {
|
if (setup) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.blue('Starting interactive response language setup...')
|
chalk.blue('Starting interactive response language setup...')
|
||||||
@@ -3769,7 +3740,6 @@ Examples:
|
|||||||
`❌ Error setting response language: ${result.error.message}`
|
`❌ Error setting response language: ${result.error.message}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3794,13 +3764,12 @@ Examples:
|
|||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const sourceId = options.from;
|
const sourceId = options.from;
|
||||||
const destinationId = options.to;
|
const destinationId = options.to;
|
||||||
const tag = taskMaster.getCurrentTag();
|
const tag = options.tag;
|
||||||
|
|
||||||
if (!sourceId || !destinationId) {
|
if (!sourceId || !destinationId) {
|
||||||
console.error(
|
console.error(
|
||||||
@@ -4228,19 +4197,15 @@ Examples:
|
|||||||
'-s, --status <status>',
|
'-s, --status <status>',
|
||||||
'Show only tasks matching this status (e.g., pending, done)'
|
'Show only tasks matching this status (e.g., pending, done)'
|
||||||
)
|
)
|
||||||
.option('-t, --tag <tag>', 'Tag to use for the task list (default: master)')
|
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
// Initialize TaskMaster
|
// Initialize TaskMaster
|
||||||
const taskMaster = initTaskMaster({
|
const taskMaster = initTaskMaster({
|
||||||
tasksPath: options.file || true,
|
tasksPath: options.file || true
|
||||||
tag: options.tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const withSubtasks = options.withSubtasks || false;
|
const withSubtasks = options.withSubtasks || false;
|
||||||
const status = options.status || null;
|
const status = options.status || null;
|
||||||
|
|
||||||
const tag = taskMaster.getCurrentTag();
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
chalk.blue(
|
chalk.blue(
|
||||||
`📝 Syncing tasks to README.md${withSubtasks ? ' (with subtasks)' : ''}${status ? ` (status: ${status})` : ''}...`
|
`📝 Syncing tasks to README.md${withSubtasks ? ' (with subtasks)' : ''}${status ? ` (status: ${status})` : ''}...`
|
||||||
@@ -4250,8 +4215,7 @@ Examples:
|
|||||||
const success = await syncTasksToReadme(taskMaster.getProjectRoot(), {
|
const success = await syncTasksToReadme(taskMaster.getProjectRoot(), {
|
||||||
withSubtasks,
|
withSubtasks,
|
||||||
status,
|
status,
|
||||||
tasksPath: taskMaster.getTasksPath(),
|
tasksPath: taskMaster.getTasksPath()
|
||||||
tag
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -4973,33 +4937,6 @@ async function runCLI(argv = process.argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve the final complexity-report path.
|
|
||||||
* Rules:
|
|
||||||
* 1. If caller passes --output, always respect it.
|
|
||||||
* 2. If no explicit output AND tag === 'master' → default report file
|
|
||||||
* 3. If no explicit output AND tag !== 'master' → append _<tag>.json
|
|
||||||
*
|
|
||||||
* @param {string|undefined} outputOpt --output value from CLI (may be undefined)
|
|
||||||
* @param {string} targetTag resolved tag (defaults to 'master')
|
|
||||||
* @param {string} projectRoot absolute project root
|
|
||||||
* @returns {string} absolute path for the report
|
|
||||||
*/
|
|
||||||
export function resolveComplexityReportPath({
|
|
||||||
projectRoot,
|
|
||||||
tag = 'master',
|
|
||||||
output // may be undefined
|
|
||||||
}) {
|
|
||||||
// 1. user knows best
|
|
||||||
if (output) {
|
|
||||||
return path.isAbsolute(output) ? output : path.join(projectRoot, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. default naming
|
|
||||||
const base = path.join(projectRoot, COMPLEXITY_REPORT_FILE);
|
|
||||||
return tag !== 'master' ? base.replace('.json', `_${tag}.json`) : base;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
registerCommands,
|
registerCommands,
|
||||||
setupCLI,
|
setupCLI,
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { AI_COMMAND_NAMES } from '../../src/constants/commands.js';
|
import { fileURLToPath } from 'url';
|
||||||
|
import { log, findProjectRoot, resolveEnvVariable, isEmpty } from './utils.js';
|
||||||
import {
|
import {
|
||||||
LEGACY_CONFIG_FILE,
|
LEGACY_CONFIG_FILE,
|
||||||
TASKMASTER_DIR
|
TASKMASTER_DIR
|
||||||
} from '../../src/constants/paths.js';
|
} from '../../src/constants/paths.js';
|
||||||
|
import { findConfigPath } from '../../src/utils/path-utils.js';
|
||||||
import {
|
import {
|
||||||
ALL_PROVIDERS,
|
VALIDATED_PROVIDERS,
|
||||||
CUSTOM_PROVIDERS,
|
CUSTOM_PROVIDERS,
|
||||||
CUSTOM_PROVIDERS_ARRAY,
|
CUSTOM_PROVIDERS_ARRAY,
|
||||||
VALIDATED_PROVIDERS
|
ALL_PROVIDERS
|
||||||
} from '../../src/constants/providers.js';
|
} from '../../src/constants/providers.js';
|
||||||
import { findConfigPath } from '../../src/utils/path-utils.js';
|
import { AI_COMMAND_NAMES } from '../../src/constants/commands.js';
|
||||||
import { findProjectRoot, isEmpty, log, resolveEnvVariable } from './utils.js';
|
|
||||||
|
|
||||||
// Calculate __dirname in ESM
|
// Calculate __dirname in ESM
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
@@ -641,7 +641,6 @@ function isApiKeySet(providerName, session = null, projectRoot = null) {
|
|||||||
azure: 'AZURE_OPENAI_API_KEY',
|
azure: 'AZURE_OPENAI_API_KEY',
|
||||||
openrouter: 'OPENROUTER_API_KEY',
|
openrouter: 'OPENROUTER_API_KEY',
|
||||||
xai: 'XAI_API_KEY',
|
xai: 'XAI_API_KEY',
|
||||||
groq: 'GROQ_API_KEY',
|
|
||||||
vertex: 'GOOGLE_API_KEY', // Vertex uses the same key as Google
|
vertex: 'GOOGLE_API_KEY', // Vertex uses the same key as Google
|
||||||
'claude-code': 'CLAUDE_CODE_API_KEY', // Not actually used, but included for consistency
|
'claude-code': 'CLAUDE_CODE_API_KEY', // Not actually used, but included for consistency
|
||||||
bedrock: 'AWS_ACCESS_KEY_ID' // Bedrock uses AWS credentials
|
bedrock: 'AWS_ACCESS_KEY_ID' // Bedrock uses AWS credentials
|
||||||
@@ -727,10 +726,6 @@ function getMcpApiKeyStatus(providerName, projectRoot = null) {
|
|||||||
apiKeyToCheck = mcpEnv.XAI_API_KEY;
|
apiKeyToCheck = mcpEnv.XAI_API_KEY;
|
||||||
placeholderValue = 'YOUR_XAI_API_KEY_HERE';
|
placeholderValue = 'YOUR_XAI_API_KEY_HERE';
|
||||||
break;
|
break;
|
||||||
case 'groq':
|
|
||||||
apiKeyToCheck = mcpEnv.GROQ_API_KEY;
|
|
||||||
placeholderValue = 'YOUR_GROQ_API_KEY_HERE';
|
|
||||||
break;
|
|
||||||
case 'ollama':
|
case 'ollama':
|
||||||
return true; // No key needed
|
return true; // No key needed
|
||||||
case 'claude-code':
|
case 'claude-code':
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import { generateTaskFiles } from './task-manager.js';
|
|||||||
* @param {number|string} taskId - ID of the task to add dependency to
|
* @param {number|string} taskId - ID of the task to add dependency to
|
||||||
* @param {number|string} dependencyId - ID of the task to add as dependency
|
* @param {number|string} dependencyId - ID of the task to add as dependency
|
||||||
* @param {Object} context - Context object containing projectRoot and tag information
|
* @param {Object} context - Context object containing projectRoot and tag information
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
*/
|
*/
|
||||||
async function addDependency(tasksPath, taskId, dependencyId, context = {}) {
|
async function addDependency(tasksPath, taskId, dependencyId, context = {}) {
|
||||||
log('info', `Adding dependency ${dependencyId} to task ${taskId}...`);
|
log('info', `Adding dependency ${dependencyId} to task ${taskId}...`);
|
||||||
@@ -216,8 +214,6 @@ async function addDependency(tasksPath, taskId, dependencyId, context = {}) {
|
|||||||
* @param {number|string} taskId - ID of the task to remove dependency from
|
* @param {number|string} taskId - ID of the task to remove dependency from
|
||||||
* @param {number|string} dependencyId - ID of the task to remove as dependency
|
* @param {number|string} dependencyId - ID of the task to remove as dependency
|
||||||
* @param {Object} context - Context object containing projectRoot and tag information
|
* @param {Object} context - Context object containing projectRoot and tag information
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
*/
|
*/
|
||||||
async function removeDependency(tasksPath, taskId, dependencyId, context = {}) {
|
async function removeDependency(tasksPath, taskId, dependencyId, context = {}) {
|
||||||
log('info', `Removing dependency ${dependencyId} from task ${taskId}...`);
|
log('info', `Removing dependency ${dependencyId} from task ${taskId}...`);
|
||||||
|
|||||||
@@ -295,16 +295,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"groq": [
|
"groq": [
|
||||||
{
|
|
||||||
"id": "moonshotai/kimi-k2-instruct",
|
|
||||||
"swe_score": 0.66,
|
|
||||||
"cost_per_1m_tokens": {
|
|
||||||
"input": 1.0,
|
|
||||||
"output": 3.0
|
|
||||||
},
|
|
||||||
"allowed_roles": ["main", "fallback"],
|
|
||||||
"max_tokens": 131072
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "llama-3.3-70b-versatile",
|
"id": "llama-3.3-70b-versatile",
|
||||||
"swe_score": 0.55,
|
"swe_score": 0.55,
|
||||||
|
|||||||
@@ -91,12 +91,11 @@ function createEndMarker() {
|
|||||||
* @param {string} options.status - Filter by status (e.g., 'pending', 'done')
|
* @param {string} options.status - Filter by status (e.g., 'pending', 'done')
|
||||||
* @param {string} options.tasksPath - Custom path to tasks.json
|
* @param {string} options.tasksPath - Custom path to tasks.json
|
||||||
* @returns {boolean} - True if sync was successful, false otherwise
|
* @returns {boolean} - True if sync was successful, false otherwise
|
||||||
* TODO: Add tag support - this is not currently supported how we want to handle this - Parthy
|
|
||||||
*/
|
*/
|
||||||
export async function syncTasksToReadme(projectRoot = null, options = {}) {
|
export async function syncTasksToReadme(projectRoot = null, options = {}) {
|
||||||
try {
|
try {
|
||||||
const actualProjectRoot = projectRoot || findProjectRoot() || '.';
|
const actualProjectRoot = projectRoot || findProjectRoot() || '.';
|
||||||
const { withSubtasks = false, status, tasksPath, tag } = options;
|
const { withSubtasks = false, status, tasksPath } = options;
|
||||||
|
|
||||||
// Get current tasks using the list-tasks functionality with markdown-readme format
|
// Get current tasks using the list-tasks functionality with markdown-readme format
|
||||||
const tasksOutput = await listTasks(
|
const tasksOutput = await listTasks(
|
||||||
@@ -105,8 +104,7 @@ export async function syncTasksToReadme(projectRoot = null, options = {}) {
|
|||||||
status,
|
status,
|
||||||
null,
|
null,
|
||||||
withSubtasks,
|
withSubtasks,
|
||||||
'markdown-readme',
|
'markdown-readme'
|
||||||
{ projectRoot, tag }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!tasksOutput) {
|
if (!tasksOutput) {
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import generateTaskFiles from './generate-task-files.js';
|
|||||||
* @param {Object} newSubtaskData - Data for creating a new subtask (used if existingTaskId is null)
|
* @param {Object} newSubtaskData - Data for creating a new subtask (used if existingTaskId is null)
|
||||||
* @param {boolean} generateFiles - Whether to regenerate task files after adding the subtask
|
* @param {boolean} generateFiles - Whether to regenerate task files after adding the subtask
|
||||||
* @param {Object} context - Context object containing projectRoot and tag information
|
* @param {Object} context - Context object containing projectRoot and tag information
|
||||||
* @param {string} context.projectRoot - Project root path
|
|
||||||
* @param {string} context.tag - Tag for the task
|
|
||||||
* @returns {Object} The newly created or converted subtask
|
* @returns {Object} The newly created or converted subtask
|
||||||
*/
|
*/
|
||||||
async function addSubtask(
|
async function addSubtask(
|
||||||
@@ -24,12 +22,13 @@ async function addSubtask(
|
|||||||
generateFiles = true,
|
generateFiles = true,
|
||||||
context = {}
|
context = {}
|
||||||
) {
|
) {
|
||||||
const { projectRoot, tag } = context;
|
|
||||||
try {
|
try {
|
||||||
log('info', `Adding subtask to parent task ${parentId}...`);
|
log('info', `Adding subtask to parent task ${parentId}...`);
|
||||||
|
|
||||||
|
const currentTag =
|
||||||
|
context.tag || getCurrentTag(context.projectRoot) || 'master';
|
||||||
// Read the existing tasks with proper context
|
// Read the existing tasks with proper context
|
||||||
const data = readJSON(tasksPath, projectRoot, tag);
|
const data = readJSON(tasksPath, context.projectRoot, currentTag);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
throw new Error(`Invalid or missing tasks file at ${tasksPath}`);
|
throw new Error(`Invalid or missing tasks file at ${tasksPath}`);
|
||||||
}
|
}
|
||||||
@@ -140,7 +139,7 @@ async function addSubtask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the updated tasks back to the file with proper context
|
// Write the updated tasks back to the file with proper context
|
||||||
writeJSON(tasksPath, data, projectRoot, tag);
|
writeJSON(tasksPath, data, context.projectRoot, currentTag);
|
||||||
|
|
||||||
// Generate task files if requested
|
// Generate task files if requested
|
||||||
if (generateFiles) {
|
if (generateFiles) {
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ import {
|
|||||||
truncate,
|
truncate,
|
||||||
ensureTagMetadata,
|
ensureTagMetadata,
|
||||||
performCompleteTagMigration,
|
performCompleteTagMigration,
|
||||||
markMigrationForNotice
|
markMigrationForNotice,
|
||||||
|
getCurrentTag
|
||||||
} 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 } from '../config-manager.js';
|
||||||
@@ -92,7 +93,7 @@ function getAllTasks(rawData) {
|
|||||||
* @param {string} [context.projectRoot] - Project root path (for MCP/env fallback)
|
* @param {string} [context.projectRoot] - Project root path (for MCP/env fallback)
|
||||||
* @param {string} [context.commandName] - The name of the command being executed (for telemetry)
|
* @param {string} [context.commandName] - The name of the command being executed (for telemetry)
|
||||||
* @param {string} [context.outputType] - The output type ('cli' or 'mcp', for telemetry)
|
* @param {string} [context.outputType] - The output type ('cli' or 'mcp', for telemetry)
|
||||||
* @param {string} [context.tag] - Tag for the task (optional)
|
* @param {string} [tag] - Tag for the task (optional)
|
||||||
* @returns {Promise<object>} An object containing newTaskId and telemetryData
|
* @returns {Promise<object>} An object containing newTaskId and telemetryData
|
||||||
*/
|
*/
|
||||||
async function addTask(
|
async function addTask(
|
||||||
@@ -103,10 +104,10 @@ async function addTask(
|
|||||||
context = {},
|
context = {},
|
||||||
outputFormat = 'text', // Default to text for CLI
|
outputFormat = 'text', // Default to text for CLI
|
||||||
manualTaskData = null,
|
manualTaskData = null,
|
||||||
useResearch = false
|
useResearch = false,
|
||||||
|
tag = null
|
||||||
) {
|
) {
|
||||||
const { session, mcpLog, projectRoot, commandName, outputType, tag } =
|
const { session, mcpLog, projectRoot, commandName, outputType } = context;
|
||||||
context;
|
|
||||||
const isMCP = !!mcpLog;
|
const isMCP = !!mcpLog;
|
||||||
|
|
||||||
// Create a consistent logFn object regardless of context
|
// Create a consistent logFn object regardless of context
|
||||||
@@ -223,7 +224,7 @@ async function addTask(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Read the existing tasks - IMPORTANT: Read the raw data without tag resolution
|
// Read the existing tasks - IMPORTANT: Read the raw data without tag resolution
|
||||||
let rawData = readJSON(tasksPath, projectRoot, tag); // No tag parameter
|
let rawData = readJSON(tasksPath, projectRoot); // No tag parameter
|
||||||
|
|
||||||
// Handle the case where readJSON returns resolved data with _rawTaggedData
|
// Handle the case where readJSON returns resolved data with _rawTaggedData
|
||||||
if (rawData && rawData._rawTaggedData) {
|
if (rawData && rawData._rawTaggedData) {
|
||||||
@@ -278,7 +279,8 @@ async function addTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use the provided tag, or the current active tag, or default to 'master'
|
// Use the provided tag, or the current active tag, or default to 'master'
|
||||||
const targetTag = tag;
|
const targetTag =
|
||||||
|
tag || context.tag || getCurrentTag(projectRoot) || 'master';
|
||||||
|
|
||||||
// Ensure the target tag exists
|
// Ensure the target tag exists
|
||||||
if (!rawData[targetTag]) {
|
if (!rawData[targetTag]) {
|
||||||
@@ -387,7 +389,7 @@ async function addTask(
|
|||||||
report(`Generating task data with AI with prompt:\n${prompt}`, 'info');
|
report(`Generating task data with AI with prompt:\n${prompt}`, 'info');
|
||||||
|
|
||||||
// --- Use the new ContextGatherer ---
|
// --- Use the new ContextGatherer ---
|
||||||
const contextGatherer = new ContextGatherer(projectRoot, tag);
|
const contextGatherer = new ContextGatherer(projectRoot);
|
||||||
const gatherResult = await contextGatherer.gather({
|
const gatherResult = await contextGatherer.gather({
|
||||||
semanticQuery: prompt,
|
semanticQuery: prompt,
|
||||||
dependencyTasks: numericDependencies,
|
dependencyTasks: numericDependencies,
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import {
|
|||||||
COMPLEXITY_REPORT_FILE,
|
COMPLEXITY_REPORT_FILE,
|
||||||
LEGACY_TASKS_FILE
|
LEGACY_TASKS_FILE
|
||||||
} from '../../../src/constants/paths.js';
|
} from '../../../src/constants/paths.js';
|
||||||
import { resolveComplexityReportOutputPath } from '../../../src/utils/path-utils.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 } from '../utils.js';
|
import { flattenTasksWithSubtasks } from '../utils.js';
|
||||||
@@ -72,7 +71,6 @@ Do not include any explanatory text, markdown formatting, or code block markers
|
|||||||
* @param {string|number} [options.threshold] - Complexity threshold
|
* @param {string|number} [options.threshold] - Complexity threshold
|
||||||
* @param {boolean} [options.research] - Use research role
|
* @param {boolean} [options.research] - Use research role
|
||||||
* @param {string} [options.projectRoot] - Project root path (for MCP/env fallback).
|
* @param {string} [options.projectRoot] - Project root path (for MCP/env fallback).
|
||||||
* @param {string} [options.tag] - Tag for the task
|
|
||||||
* @param {string} [options.id] - Comma-separated list of task IDs to analyze specifically
|
* @param {string} [options.id] - Comma-separated list of task IDs to analyze specifically
|
||||||
* @param {number} [options.from] - Starting task ID in a range to analyze
|
* @param {number} [options.from] - Starting task ID in a range to analyze
|
||||||
* @param {number} [options.to] - Ending task ID in a range to analyze
|
* @param {number} [options.to] - Ending task ID in a range to analyze
|
||||||
@@ -86,6 +84,7 @@ Do not include any explanatory text, markdown formatting, or code block markers
|
|||||||
async function analyzeTaskComplexity(options, context = {}) {
|
async function analyzeTaskComplexity(options, context = {}) {
|
||||||
const { session, mcpLog } = context;
|
const { session, mcpLog } = context;
|
||||||
const tasksPath = options.file || LEGACY_TASKS_FILE;
|
const tasksPath = options.file || LEGACY_TASKS_FILE;
|
||||||
|
const outputPath = options.output || COMPLEXITY_REPORT_FILE;
|
||||||
const thresholdScore = parseFloat(options.threshold || '5');
|
const thresholdScore = parseFloat(options.threshold || '5');
|
||||||
const useResearch = options.research || false;
|
const useResearch = options.research || false;
|
||||||
const projectRoot = options.projectRoot;
|
const projectRoot = options.projectRoot;
|
||||||
@@ -110,13 +109,6 @@ async function analyzeTaskComplexity(options, context = {}) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolve output path using tag-aware resolution
|
|
||||||
const outputPath = resolveComplexityReportOutputPath(
|
|
||||||
options.output,
|
|
||||||
{ projectRoot, tag },
|
|
||||||
reportLog
|
|
||||||
);
|
|
||||||
|
|
||||||
if (outputFormat === 'text') {
|
if (outputFormat === 'text') {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.blue(
|
chalk.blue(
|
||||||
@@ -228,7 +220,7 @@ async function analyzeTaskComplexity(options, context = {}) {
|
|||||||
let gatheredContext = '';
|
let gatheredContext = '';
|
||||||
if (originalData && originalData.tasks.length > 0) {
|
if (originalData && originalData.tasks.length > 0) {
|
||||||
try {
|
try {
|
||||||
const contextGatherer = new ContextGatherer(projectRoot, tag);
|
const contextGatherer = new ContextGatherer(projectRoot);
|
||||||
const allTasksFlat = flattenTasksWithSubtasks(originalData.tasks);
|
const allTasksFlat = flattenTasksWithSubtasks(originalData.tasks);
|
||||||
const fuzzySearch = new FuzzyTaskSearch(
|
const fuzzySearch = new FuzzyTaskSearch(
|
||||||
allTasksFlat,
|
allTasksFlat,
|
||||||
@@ -543,7 +535,7 @@ async function analyzeTaskComplexity(options, context = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge with existing report - only keep entries from the current tag
|
// Merge with existing report
|
||||||
let finalComplexityAnalysis = [];
|
let finalComplexityAnalysis = [];
|
||||||
|
|
||||||
if (existingReport && Array.isArray(existingReport.complexityAnalysis)) {
|
if (existingReport && Array.isArray(existingReport.complexityAnalysis)) {
|
||||||
@@ -552,14 +544,10 @@ async function analyzeTaskComplexity(options, context = {}) {
|
|||||||
complexityAnalysis.map((item) => item.taskId)
|
complexityAnalysis.map((item) => item.taskId)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Keep existing entries that weren't in this analysis run AND belong to the current tag
|
// Keep existing entries that weren't in this analysis run
|
||||||
// We determine tag membership by checking if the task ID exists in the current tag's tasks
|
|
||||||
const currentTagTaskIds = new Set(tasksData.tasks.map((t) => t.id));
|
|
||||||
const existingEntriesNotAnalyzed =
|
const existingEntriesNotAnalyzed =
|
||||||
existingReport.complexityAnalysis.filter(
|
existingReport.complexityAnalysis.filter(
|
||||||
(item) =>
|
(item) => !analyzedTaskIds.has(item.taskId)
|
||||||
!analyzedTaskIds.has(item.taskId) &&
|
|
||||||
currentTagTaskIds.has(item.taskId) // Only keep entries for tasks in current tag
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Combine with new analysis
|
// Combine with new analysis
|
||||||
@@ -569,7 +557,7 @@ async function analyzeTaskComplexity(options, context = {}) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
reportLog(
|
reportLog(
|
||||||
`Merged ${complexityAnalysis.length} new analyses with ${existingEntriesNotAnalyzed.length} existing entries from current tag`,
|
`Merged ${complexityAnalysis.length} new analyses with ${existingEntriesNotAnalyzed.length} existing entries`,
|
||||||
'info'
|
'info'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import { displayBanner } from '../ui.js';
|
|||||||
* @param {string} tasksPath - Path to the tasks.json file
|
* @param {string} tasksPath - Path to the tasks.json file
|
||||||
* @param {string} taskIds - Task IDs to clear subtasks from
|
* @param {string} taskIds - Task IDs to clear subtasks from
|
||||||
* @param {Object} context - Context object containing projectRoot and tag
|
* @param {Object} context - Context object containing projectRoot and tag
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
*/
|
*/
|
||||||
function clearSubtasks(tasksPath, taskIds, context = {}) {
|
function clearSubtasks(tasksPath, taskIds, context = {}) {
|
||||||
const { projectRoot, tag } = context;
|
const { projectRoot, tag } = context;
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import boxen from 'boxen';
|
|||||||
* @param {Object} context - Context object containing session and mcpLog.
|
* @param {Object} context - Context object containing session and mcpLog.
|
||||||
* @param {Object} [context.session] - Session object from MCP.
|
* @param {Object} [context.session] - Session object from MCP.
|
||||||
* @param {Object} [context.mcpLog] - MCP logger object.
|
* @param {Object} [context.mcpLog] - MCP logger object.
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
* @param {string} [outputFormat='text'] - Output format ('text' or 'json'). MCP calls should use 'json'.
|
* @param {string} [outputFormat='text'] - Output format ('text' or 'json'). MCP calls should use 'json'.
|
||||||
* @returns {Promise<{success: boolean, expandedCount: number, failedCount: number, skippedCount: number, tasksToExpand: number, telemetryData: Array<Object>}>} - Result summary.
|
* @returns {Promise<{success: boolean, expandedCount: number, failedCount: number, skippedCount: number, tasksToExpand: number, telemetryData: Array<Object>}>} - Result summary.
|
||||||
*/
|
*/
|
||||||
@@ -34,7 +32,12 @@ async function expandAllTasks(
|
|||||||
context = {},
|
context = {},
|
||||||
outputFormat = 'text' // Assume text default for CLI
|
outputFormat = 'text' // Assume text default for CLI
|
||||||
) {
|
) {
|
||||||
const { session, mcpLog, projectRoot: providedProjectRoot, tag } = context;
|
const {
|
||||||
|
session,
|
||||||
|
mcpLog,
|
||||||
|
projectRoot: providedProjectRoot,
|
||||||
|
tag: contextTag
|
||||||
|
} = context;
|
||||||
const isMCPCall = !!mcpLog; // Determine if called from MCP
|
const isMCPCall = !!mcpLog; // Determine if called from MCP
|
||||||
|
|
||||||
const projectRoot = providedProjectRoot || findProjectRoot();
|
const projectRoot = providedProjectRoot || findProjectRoot();
|
||||||
@@ -76,7 +79,7 @@ async function expandAllTasks(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info(`Reading tasks from ${tasksPath}`);
|
logger.info(`Reading tasks from ${tasksPath}`);
|
||||||
const data = readJSON(tasksPath, projectRoot, tag);
|
const data = readJSON(tasksPath, projectRoot, contextTag);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
throw new Error(`Invalid tasks data in ${tasksPath}`);
|
throw new Error(`Invalid tasks data in ${tasksPath}`);
|
||||||
}
|
}
|
||||||
@@ -126,7 +129,7 @@ async function expandAllTasks(
|
|||||||
numSubtasks,
|
numSubtasks,
|
||||||
useResearch,
|
useResearch,
|
||||||
additionalContext,
|
additionalContext,
|
||||||
{ ...context, projectRoot, tag: data.tag || tag }, // Pass the whole context object with projectRoot and resolved tag
|
{ ...context, projectRoot, tag: data.tag || contextTag }, // Pass the whole context object with projectRoot and resolved tag
|
||||||
force
|
force
|
||||||
);
|
);
|
||||||
expandedCount++;
|
expandedCount++;
|
||||||
|
|||||||
@@ -40,10 +40,8 @@ const subtaskSchema = z
|
|||||||
.min(10)
|
.min(10)
|
||||||
.describe('Detailed description of the subtask'),
|
.describe('Detailed description of the subtask'),
|
||||||
dependencies: z
|
dependencies: z
|
||||||
.array(z.string())
|
.array(z.number().int())
|
||||||
.describe(
|
.describe('IDs of prerequisite subtasks within this expansion'),
|
||||||
'Array of subtask dependencies within the same parent task. Use format ["parentTaskId.1", "parentTaskId.2"]. Subtasks can only depend on siblings, not external tasks.'
|
|
||||||
),
|
|
||||||
details: z.string().min(20).describe('Implementation details and guidance'),
|
details: z.string().min(20).describe('Implementation details and guidance'),
|
||||||
status: z
|
status: z
|
||||||
.string()
|
.string()
|
||||||
@@ -237,10 +235,12 @@ function parseSubtasksFromText(
|
|||||||
...rawSubtask,
|
...rawSubtask,
|
||||||
id: currentId,
|
id: currentId,
|
||||||
dependencies: Array.isArray(rawSubtask.dependencies)
|
dependencies: Array.isArray(rawSubtask.dependencies)
|
||||||
? rawSubtask.dependencies.filter(
|
? rawSubtask.dependencies
|
||||||
(dep) =>
|
.map((dep) => (typeof dep === 'string' ? parseInt(dep, 10) : dep))
|
||||||
typeof dep === 'string' && dep.startsWith(`${parentTaskId}.`)
|
.filter(
|
||||||
)
|
(depId) =>
|
||||||
|
!Number.isNaN(depId) && depId >= startId && depId < currentId
|
||||||
|
)
|
||||||
: [],
|
: [],
|
||||||
status: 'pending'
|
status: 'pending'
|
||||||
};
|
};
|
||||||
@@ -290,8 +290,6 @@ function parseSubtasksFromText(
|
|||||||
* @param {Object} context - Context object containing session and mcpLog.
|
* @param {Object} context - Context object containing session and mcpLog.
|
||||||
* @param {Object} [context.session] - Session object from MCP.
|
* @param {Object} [context.session] - Session object from MCP.
|
||||||
* @param {Object} [context.mcpLog] - MCP logger object.
|
* @param {Object} [context.mcpLog] - MCP logger object.
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
* @param {boolean} [force=false] - If true, replace existing subtasks; otherwise, append.
|
* @param {boolean} [force=false] - If true, replace existing subtasks; otherwise, append.
|
||||||
* @returns {Promise<Object>} The updated parent task object with new subtasks.
|
* @returns {Promise<Object>} The updated parent task object with new subtasks.
|
||||||
* @throws {Error} If task not found, AI service fails, or parsing fails.
|
* @throws {Error} If task not found, AI service fails, or parsing fails.
|
||||||
@@ -305,13 +303,7 @@ async function expandTask(
|
|||||||
context = {},
|
context = {},
|
||||||
force = false
|
force = false
|
||||||
) {
|
) {
|
||||||
const {
|
const { session, mcpLog, projectRoot: contextProjectRoot, tag } = context;
|
||||||
session,
|
|
||||||
mcpLog,
|
|
||||||
projectRoot: contextProjectRoot,
|
|
||||||
tag,
|
|
||||||
complexityReportPath
|
|
||||||
} = context;
|
|
||||||
const outputFormat = mcpLog ? 'json' : 'text';
|
const outputFormat = mcpLog ? 'json' : 'text';
|
||||||
|
|
||||||
// Determine projectRoot: Use from context if available, otherwise derive from tasksPath
|
// Determine projectRoot: Use from context if available, otherwise derive from tasksPath
|
||||||
@@ -358,7 +350,7 @@ async function expandTask(
|
|||||||
// --- Context Gathering ---
|
// --- Context Gathering ---
|
||||||
let gatheredContext = '';
|
let gatheredContext = '';
|
||||||
try {
|
try {
|
||||||
const contextGatherer = new ContextGatherer(projectRoot, tag);
|
const contextGatherer = new ContextGatherer(projectRoot);
|
||||||
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
||||||
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'expand-task');
|
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'expand-task');
|
||||||
const searchQuery = `${task.title} ${task.description}`;
|
const searchQuery = `${task.title} ${task.description}`;
|
||||||
@@ -387,10 +379,17 @@ async function expandTask(
|
|||||||
// --- Complexity Report Integration ---
|
// --- Complexity Report Integration ---
|
||||||
let finalSubtaskCount;
|
let finalSubtaskCount;
|
||||||
let complexityReasoningContext = '';
|
let complexityReasoningContext = '';
|
||||||
|
|
||||||
|
// Use tag-aware complexity report path
|
||||||
|
const complexityReportPath = getTagAwareFilePath(
|
||||||
|
COMPLEXITY_REPORT_FILE,
|
||||||
|
tag,
|
||||||
|
projectRoot
|
||||||
|
);
|
||||||
let taskAnalysis = null;
|
let taskAnalysis = null;
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`Looking for complexity report at: ${complexityReportPath}${tag !== 'master' ? ` (tag-specific for '${tag}')` : ''}`
|
`Looking for complexity report at: ${complexityReportPath}${tag && tag !== 'master' ? ` (tag-specific for '${tag}')` : ''}`
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -12,20 +12,16 @@ import { getDebugFlag } from '../config-manager.js';
|
|||||||
* @param {string} tasksPath - Path to the tasks.json file
|
* @param {string} tasksPath - Path to the tasks.json file
|
||||||
* @param {string} outputDir - Output directory for task files
|
* @param {string} outputDir - Output directory for task files
|
||||||
* @param {Object} options - Additional options (mcpLog for MCP mode, projectRoot, tag)
|
* @param {Object} options - Additional options (mcpLog for MCP mode, projectRoot, tag)
|
||||||
* @param {string} [options.projectRoot] - Project root path
|
|
||||||
* @param {string} [options.tag] - Tag for the task
|
|
||||||
* @param {Object} [options.mcpLog] - MCP logger object
|
|
||||||
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
|
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
|
||||||
*/
|
*/
|
||||||
function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
||||||
try {
|
try {
|
||||||
const isMcpMode = !!options?.mcpLog;
|
const isMcpMode = !!options?.mcpLog;
|
||||||
const { projectRoot, tag } = options;
|
|
||||||
|
|
||||||
// 1. Read the raw data structure, ensuring we have all tags.
|
// 1. Read the raw data structure, ensuring we have all tags.
|
||||||
// We call readJSON without a specific tag to get the resolved default view,
|
// We call readJSON without a specific tag to get the resolved default view,
|
||||||
// which correctly contains the full structure in `_rawTaggedData`.
|
// which correctly contains the full structure in `_rawTaggedData`.
|
||||||
const resolvedData = readJSON(tasksPath, projectRoot, tag);
|
const resolvedData = readJSON(tasksPath, options.projectRoot);
|
||||||
if (!resolvedData) {
|
if (!resolvedData) {
|
||||||
throw new Error(`Could not read or parse tasks file: ${tasksPath}`);
|
throw new Error(`Could not read or parse tasks file: ${tasksPath}`);
|
||||||
}
|
}
|
||||||
@@ -33,10 +29,13 @@ function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
|||||||
const rawData = resolvedData._rawTaggedData || resolvedData;
|
const rawData = resolvedData._rawTaggedData || resolvedData;
|
||||||
|
|
||||||
// 2. Determine the target tag we need to generate files for.
|
// 2. Determine the target tag we need to generate files for.
|
||||||
const tagData = rawData[tag];
|
const targetTag = options.tag || resolvedData.tag || 'master';
|
||||||
|
const tagData = rawData[targetTag];
|
||||||
|
|
||||||
if (!tagData || !tagData.tasks) {
|
if (!tagData || !tagData.tasks) {
|
||||||
throw new Error(`Tag '${tag}' not found or has no tasks in the data.`);
|
throw new Error(
|
||||||
|
`Tag '${targetTag}' not found or has no tasks in the data.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const tasksForGeneration = tagData.tasks;
|
const tasksForGeneration = tagData.tasks;
|
||||||
|
|
||||||
@@ -47,15 +46,15 @@ function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
|||||||
|
|
||||||
log(
|
log(
|
||||||
'info',
|
'info',
|
||||||
`Preparing to regenerate ${tasksForGeneration.length} task files for tag '${tag}'`
|
`Preparing to regenerate ${tasksForGeneration.length} task files for tag '${targetTag}'`
|
||||||
);
|
);
|
||||||
|
|
||||||
// 3. Validate dependencies using the FULL, raw data structure to prevent data loss.
|
// 3. Validate dependencies using the FULL, raw data structure to prevent data loss.
|
||||||
validateAndFixDependencies(
|
validateAndFixDependencies(
|
||||||
rawData, // Pass the entire object with all tags
|
rawData, // Pass the entire object with all tags
|
||||||
tasksPath,
|
tasksPath,
|
||||||
projectRoot,
|
options.projectRoot,
|
||||||
tag // Provide the current tag context for the operation
|
targetTag // Provide the current tag context for the operation
|
||||||
);
|
);
|
||||||
|
|
||||||
const allTasksInTag = tagData.tasks;
|
const allTasksInTag = tagData.tasks;
|
||||||
@@ -67,14 +66,14 @@ function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
|||||||
const files = fs.readdirSync(outputDir);
|
const files = fs.readdirSync(outputDir);
|
||||||
// Tag-aware file patterns: master -> task_001.txt, other tags -> task_001_tagname.txt
|
// Tag-aware file patterns: master -> task_001.txt, other tags -> task_001_tagname.txt
|
||||||
const masterFilePattern = /^task_(\d+)\.txt$/;
|
const masterFilePattern = /^task_(\d+)\.txt$/;
|
||||||
const taggedFilePattern = new RegExp(`^task_(\\d+)_${tag}\\.txt$`);
|
const taggedFilePattern = new RegExp(`^task_(\\d+)_${targetTag}\\.txt$`);
|
||||||
|
|
||||||
const orphanedFiles = files.filter((file) => {
|
const orphanedFiles = files.filter((file) => {
|
||||||
let match = null;
|
let match = null;
|
||||||
let fileTaskId = null;
|
let fileTaskId = null;
|
||||||
|
|
||||||
// Check if file belongs to current tag
|
// Check if file belongs to current tag
|
||||||
if (tag === 'master') {
|
if (targetTag === 'master') {
|
||||||
match = file.match(masterFilePattern);
|
match = file.match(masterFilePattern);
|
||||||
if (match) {
|
if (match) {
|
||||||
fileTaskId = parseInt(match[1], 10);
|
fileTaskId = parseInt(match[1], 10);
|
||||||
@@ -95,7 +94,7 @@ function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
|||||||
if (orphanedFiles.length > 0) {
|
if (orphanedFiles.length > 0) {
|
||||||
log(
|
log(
|
||||||
'info',
|
'info',
|
||||||
`Found ${orphanedFiles.length} orphaned task files to remove for tag '${tag}'`
|
`Found ${orphanedFiles.length} orphaned task files to remove for tag '${targetTag}'`
|
||||||
);
|
);
|
||||||
orphanedFiles.forEach((file) => {
|
orphanedFiles.forEach((file) => {
|
||||||
const filePath = path.join(outputDir, file);
|
const filePath = path.join(outputDir, file);
|
||||||
@@ -109,13 +108,13 @@ function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate task files for the target tag
|
// Generate task files for the target tag
|
||||||
log('info', `Generating individual task files for tag '${tag}'...`);
|
log('info', `Generating individual task files for tag '${targetTag}'...`);
|
||||||
tasksForGeneration.forEach((task) => {
|
tasksForGeneration.forEach((task) => {
|
||||||
// Tag-aware file naming: master -> task_001.txt, other tags -> task_001_tagname.txt
|
// Tag-aware file naming: master -> task_001.txt, other tags -> task_001_tagname.txt
|
||||||
const taskFileName =
|
const taskFileName =
|
||||||
tag === 'master'
|
targetTag === 'master'
|
||||||
? `task_${task.id.toString().padStart(3, '0')}.txt`
|
? `task_${task.id.toString().padStart(3, '0')}.txt`
|
||||||
: `task_${task.id.toString().padStart(3, '0')}_${tag}.txt`;
|
: `task_${task.id.toString().padStart(3, '0')}_${targetTag}.txt`;
|
||||||
|
|
||||||
const taskPath = path.join(outputDir, taskFileName);
|
const taskPath = path.join(outputDir, taskFileName);
|
||||||
|
|
||||||
@@ -175,7 +174,7 @@ function generateTaskFiles(tasksPath, outputDir, options = {}) {
|
|||||||
|
|
||||||
log(
|
log(
|
||||||
'success',
|
'success',
|
||||||
`All ${tasksForGeneration.length} tasks for tag '${tag}' have been generated into '${outputDir}'.`
|
`All ${tasksForGeneration.length} tasks for tag '${targetTag}' have been generated into '${outputDir}'.`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isMcpMode) {
|
if (isMcpMode) {
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ import {
|
|||||||
* @param {string} reportPath - Path to the complexity report
|
* @param {string} reportPath - Path to the complexity report
|
||||||
* @param {boolean} withSubtasks - Whether to show subtasks
|
* @param {boolean} withSubtasks - Whether to show subtasks
|
||||||
* @param {string} outputFormat - Output format (text or json)
|
* @param {string} outputFormat - Output format (text or json)
|
||||||
* @param {Object} context - Context object (required)
|
* @param {string} tag - Optional tag to override current tag resolution
|
||||||
* @param {string} context.projectRoot - Project root path
|
* @param {Object} context - Optional context object containing projectRoot and other options
|
||||||
* @param {string} context.tag - Tag for the task
|
|
||||||
* @returns {Object} - Task list result for json format
|
* @returns {Object} - Task list result for json format
|
||||||
*/
|
*/
|
||||||
function listTasks(
|
function listTasks(
|
||||||
@@ -37,18 +36,18 @@ function listTasks(
|
|||||||
reportPath = null,
|
reportPath = null,
|
||||||
withSubtasks = false,
|
withSubtasks = false,
|
||||||
outputFormat = 'text',
|
outputFormat = 'text',
|
||||||
|
tag = null,
|
||||||
context = {}
|
context = {}
|
||||||
) {
|
) {
|
||||||
const { projectRoot, tag } = context;
|
|
||||||
try {
|
try {
|
||||||
// Extract projectRoot from context if provided
|
// Extract projectRoot from context if provided
|
||||||
|
const projectRoot = context.projectRoot || null;
|
||||||
const data = readJSON(tasksPath, projectRoot, tag); // Pass projectRoot to readJSON
|
const data = readJSON(tasksPath, projectRoot, tag); // Pass projectRoot to readJSON
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
throw new Error(`No valid tasks found in ${tasksPath}`);
|
throw new Error(`No valid tasks found in ${tasksPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add complexity scores to tasks if report exists
|
// Add complexity scores to tasks if report exists
|
||||||
// `reportPath` is already tag-aware (resolved at the CLI boundary).
|
|
||||||
const complexityReport = readComplexityReport(reportPath);
|
const complexityReport = readComplexityReport(reportPath);
|
||||||
// Apply complexity scores to tasks
|
// Apply complexity scores to tasks
|
||||||
if (complexityReport && complexityReport.complexityAnalysis) {
|
if (complexityReport && complexityReport.complexityAnalysis) {
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ import { findConfigPath } from '../../../src/utils/path-utils.js';
|
|||||||
import { log } from '../utils.js';
|
import { log } from '../utils.js';
|
||||||
import { CUSTOM_PROVIDERS } from '../../../src/constants/providers.js';
|
import { CUSTOM_PROVIDERS } from '../../../src/constants/providers.js';
|
||||||
|
|
||||||
// Constants
|
|
||||||
const CONFIG_MISSING_ERROR =
|
|
||||||
'The configuration file is missing. Run "task-master init" to create it.';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the list of models from OpenRouter API.
|
* Fetches the list of models from OpenRouter API.
|
||||||
* @returns {Promise<Array|null>} A promise that resolves with the list of model IDs or null if fetch fails.
|
* @returns {Promise<Array|null>} A promise that resolves with the list of model IDs or null if fetch fails.
|
||||||
@@ -172,7 +168,9 @@ async function getModelConfiguration(options = {}) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!configExists) {
|
if (!configExists) {
|
||||||
throw new Error(CONFIG_MISSING_ERROR);
|
throw new Error(
|
||||||
|
'The configuration file is missing. Run "task-master models --setup" to create it.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -300,7 +298,9 @@ async function getAvailableModelsList(options = {}) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!configExists) {
|
if (!configExists) {
|
||||||
throw new Error(CONFIG_MISSING_ERROR);
|
throw new Error(
|
||||||
|
'The configuration file is missing. Run "task-master models --setup" to create it.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -391,7 +391,9 @@ async function setModel(role, modelId, options = {}) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!configExists) {
|
if (!configExists) {
|
||||||
throw new Error(CONFIG_MISSING_ERROR);
|
throw new Error(
|
||||||
|
'The configuration file is missing. Run "task-master models --setup" to create it.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate role
|
// Validate role
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { log, readJSON, writeJSON, setTasksForTag } from '../utils.js';
|
import {
|
||||||
|
log,
|
||||||
|
readJSON,
|
||||||
|
writeJSON,
|
||||||
|
getCurrentTag,
|
||||||
|
setTasksForTag
|
||||||
|
} from '../utils.js';
|
||||||
import { isTaskDependentOn } from '../task-manager.js';
|
import { isTaskDependentOn } from '../task-manager.js';
|
||||||
import generateTaskFiles from './generate-task-files.js';
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
|
|
||||||
@@ -21,7 +27,6 @@ async function moveTask(
|
|||||||
generateFiles = false,
|
generateFiles = false,
|
||||||
options = {}
|
options = {}
|
||||||
) {
|
) {
|
||||||
const { projectRoot, tag } = options;
|
|
||||||
// Check if we have comma-separated IDs (batch move)
|
// Check if we have comma-separated IDs (batch move)
|
||||||
const sourceIds = sourceId.split(',').map((id) => id.trim());
|
const sourceIds = sourceId.split(',').map((id) => id.trim());
|
||||||
const destinationIds = destinationId.split(',').map((id) => id.trim());
|
const destinationIds = destinationId.split(',').map((id) => id.trim());
|
||||||
@@ -48,10 +53,7 @@ async function moveTask(
|
|||||||
|
|
||||||
// Generate files once at the end if requested
|
// Generate files once at the end if requested
|
||||||
if (generateFiles) {
|
if (generateFiles) {
|
||||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
await generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||||
tag: tag,
|
|
||||||
projectRoot: projectRoot
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -62,7 +64,7 @@ async function moveTask(
|
|||||||
|
|
||||||
// Single move logic
|
// Single move logic
|
||||||
// Read the raw data without tag resolution to preserve tagged structure
|
// Read the raw data without tag resolution to preserve tagged structure
|
||||||
let rawData = readJSON(tasksPath, projectRoot, tag);
|
let rawData = readJSON(tasksPath, options.projectRoot); // No tag parameter
|
||||||
|
|
||||||
// Handle the case where readJSON returns resolved data with _rawTaggedData
|
// Handle the case where readJSON returns resolved data with _rawTaggedData
|
||||||
if (rawData && rawData._rawTaggedData) {
|
if (rawData && rawData._rawTaggedData) {
|
||||||
@@ -70,19 +72,27 @@ async function moveTask(
|
|||||||
rawData = rawData._rawTaggedData;
|
rawData = rawData._rawTaggedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the current tag
|
||||||
|
const currentTag =
|
||||||
|
options.tag || getCurrentTag(options.projectRoot) || 'master';
|
||||||
|
|
||||||
// Ensure the tag exists in the raw data
|
// Ensure the tag exists in the raw data
|
||||||
if (!rawData || !rawData[tag] || !Array.isArray(rawData[tag].tasks)) {
|
if (
|
||||||
|
!rawData ||
|
||||||
|
!rawData[currentTag] ||
|
||||||
|
!Array.isArray(rawData[currentTag].tasks)
|
||||||
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid tasks file or tag "${tag}" not found at ${tasksPath}`
|
`Invalid tasks file or tag "${currentTag}" not found at ${tasksPath}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tasks for the current tag
|
// Get the tasks for the current tag
|
||||||
const tasks = rawData[tag].tasks;
|
const tasks = rawData[currentTag].tasks;
|
||||||
|
|
||||||
log(
|
log(
|
||||||
'info',
|
'info',
|
||||||
`Moving task/subtask ${sourceId} to ${destinationId} (tag: ${tag})`
|
`Moving task/subtask ${sourceId} to ${destinationId} (tag: ${currentTag})`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse source and destination IDs
|
// Parse source and destination IDs
|
||||||
@@ -106,17 +116,14 @@ async function moveTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the data structure with the modified tasks
|
// Update the data structure with the modified tasks
|
||||||
rawData[tag].tasks = tasks;
|
rawData[currentTag].tasks = tasks;
|
||||||
|
|
||||||
// Always write the data object, never the _rawTaggedData directly
|
// Always write the data object, never the _rawTaggedData directly
|
||||||
// The writeJSON function will filter out _rawTaggedData automatically
|
// The writeJSON function will filter out _rawTaggedData automatically
|
||||||
writeJSON(tasksPath, rawData, options.projectRoot, tag);
|
writeJSON(tasksPath, rawData, options.projectRoot, currentTag);
|
||||||
|
|
||||||
if (generateFiles) {
|
if (generateFiles) {
|
||||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
await generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||||
tag: tag,
|
|
||||||
projectRoot: projectRoot
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
import { generateObjectService } from '../ai-services-unified.js';
|
import { generateObjectService } from '../ai-services-unified.js';
|
||||||
import { getDebugFlag } from '../config-manager.js';
|
import { getDebugFlag } from '../config-manager.js';
|
||||||
import { getPromptManager } from '../prompt-manager.js';
|
import { getPromptManager } from '../prompt-manager.js';
|
||||||
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
import { displayAiUsageSummary } from '../ui.js';
|
import { displayAiUsageSummary } from '../ui.js';
|
||||||
|
|
||||||
// Define the Zod schema for a SINGLE task object
|
// Define the Zod schema for a SINGLE task object
|
||||||
@@ -75,7 +76,7 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
|
|||||||
const outputFormat = isMCP ? 'json' : 'text';
|
const outputFormat = isMCP ? 'json' : 'text';
|
||||||
|
|
||||||
// Use the provided tag, or the current active tag, or default to 'master'
|
// Use the provided tag, or the current active tag, or default to 'master'
|
||||||
const targetTag = tag;
|
const targetTag = tag || getCurrentTag(projectRoot) || 'master';
|
||||||
|
|
||||||
const logFn = mcpLog
|
const logFn = mcpLog
|
||||||
? mcpLog
|
? mcpLog
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import generateTaskFiles from './generate-task-files.js';
|
|||||||
* @param {boolean} convertToTask - Whether to convert the subtask to a standalone task
|
* @param {boolean} convertToTask - Whether to convert the subtask to a standalone task
|
||||||
* @param {boolean} generateFiles - Whether to regenerate task files after removing the subtask
|
* @param {boolean} generateFiles - Whether to regenerate task files after removing the subtask
|
||||||
* @param {Object} context - Context object containing projectRoot and tag information
|
* @param {Object} context - Context object containing projectRoot and tag information
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
* @returns {Object|null} The removed subtask if convertToTask is true, otherwise null
|
* @returns {Object|null} The removed subtask if convertToTask is true, otherwise null
|
||||||
*/
|
*/
|
||||||
async function removeSubtask(
|
async function removeSubtask(
|
||||||
@@ -20,12 +18,11 @@ async function removeSubtask(
|
|||||||
generateFiles = true,
|
generateFiles = true,
|
||||||
context = {}
|
context = {}
|
||||||
) {
|
) {
|
||||||
const { projectRoot, tag } = context;
|
|
||||||
try {
|
try {
|
||||||
log('info', `Removing subtask ${subtaskId}...`);
|
log('info', `Removing subtask ${subtaskId}...`);
|
||||||
|
|
||||||
// Read the existing tasks with proper context
|
// Read the existing tasks with proper context
|
||||||
const data = readJSON(tasksPath, projectRoot, tag);
|
const data = readJSON(tasksPath, context.projectRoot, context.tag);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
throw new Error(`Invalid or missing tasks file at ${tasksPath}`);
|
throw new Error(`Invalid or missing tasks file at ${tasksPath}`);
|
||||||
}
|
}
|
||||||
@@ -106,7 +103,7 @@ async function removeSubtask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the updated tasks back to the file with proper context
|
// Write the updated tasks back to the file with proper context
|
||||||
writeJSON(tasksPath, data, projectRoot, tag);
|
writeJSON(tasksPath, data, context.projectRoot, context.tag);
|
||||||
|
|
||||||
// Generate task files if requested
|
// Generate task files if requested
|
||||||
if (generateFiles) {
|
if (generateFiles) {
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import taskExists from './task-exists.js';
|
|||||||
* @param {string} tasksPath - Path to the tasks file
|
* @param {string} tasksPath - Path to the tasks file
|
||||||
* @param {string} taskIds - Comma-separated string of task/subtask IDs to remove (e.g., '5,6.1,7')
|
* @param {string} taskIds - Comma-separated string of task/subtask IDs to remove (e.g., '5,6.1,7')
|
||||||
* @param {Object} context - Context object containing projectRoot and tag information
|
* @param {Object} context - Context object containing projectRoot and tag information
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
* @returns {Object} Result object with success status, messages, and removed task info
|
* @returns {Object} Result object with success status, messages, and removed task info
|
||||||
*/
|
*/
|
||||||
async function removeTask(tasksPath, taskIds, context = {}) {
|
async function removeTask(tasksPath, taskIds, context = {}) {
|
||||||
@@ -34,7 +32,7 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Read the tasks file ONCE before the loop, preserving the full tagged structure
|
// Read the tasks file ONCE before the loop, preserving the full tagged structure
|
||||||
const rawData = readJSON(tasksPath, projectRoot, tag); // Read raw data
|
const rawData = readJSON(tasksPath, projectRoot); // Read raw data
|
||||||
if (!rawData) {
|
if (!rawData) {
|
||||||
throw new Error(`Could not read tasks file at ${tasksPath}`);
|
throw new Error(`Could not read tasks file at ${tasksPath}`);
|
||||||
}
|
}
|
||||||
@@ -42,18 +40,19 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
// Use the full tagged data if available, otherwise use the data as is
|
// Use the full tagged data if available, otherwise use the data as is
|
||||||
const fullTaggedData = rawData._rawTaggedData || rawData;
|
const fullTaggedData = rawData._rawTaggedData || rawData;
|
||||||
|
|
||||||
if (!fullTaggedData[tag] || !fullTaggedData[tag].tasks) {
|
const currentTag = tag || rawData.tag || 'master';
|
||||||
throw new Error(`Tag '${tag}' not found or has no tasks.`);
|
if (!fullTaggedData[currentTag] || !fullTaggedData[currentTag].tasks) {
|
||||||
|
throw new Error(`Tag '${currentTag}' not found or has no tasks.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tasks = fullTaggedData[tag].tasks; // Work with tasks from the correct tag
|
const tasks = fullTaggedData[currentTag].tasks; // Work with tasks from the correct tag
|
||||||
|
|
||||||
const tasksToDeleteFiles = []; // Collect IDs of main tasks whose files should be deleted
|
const tasksToDeleteFiles = []; // Collect IDs of main tasks whose files should be deleted
|
||||||
|
|
||||||
for (const taskId of taskIdsToRemove) {
|
for (const taskId of taskIdsToRemove) {
|
||||||
// Check if the task ID exists *before* attempting removal
|
// Check if the task ID exists *before* attempting removal
|
||||||
if (!taskExists(tasks, taskId)) {
|
if (!taskExists(tasks, taskId)) {
|
||||||
const errorMsg = `Task with ID ${taskId} in tag '${tag}' not found or already removed.`;
|
const errorMsg = `Task with ID ${taskId} in tag '${currentTag}' not found or already removed.`;
|
||||||
results.errors.push(errorMsg);
|
results.errors.push(errorMsg);
|
||||||
results.success = false; // Mark overall success as false if any error occurs
|
results.success = false; // Mark overall success as false if any error occurs
|
||||||
continue; // Skip to the next ID
|
continue; // Skip to the next ID
|
||||||
@@ -95,7 +94,7 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
parentTask.subtasks.splice(subtaskIndex, 1);
|
parentTask.subtasks.splice(subtaskIndex, 1);
|
||||||
|
|
||||||
results.messages.push(
|
results.messages.push(
|
||||||
`Successfully removed subtask ${taskId} from tag '${tag}'`
|
`Successfully removed subtask ${taskId} from tag '${currentTag}'`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Handle main task removal
|
// Handle main task removal
|
||||||
@@ -103,7 +102,9 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
const taskIdNum = parseInt(taskId, 10);
|
const taskIdNum = parseInt(taskId, 10);
|
||||||
const taskIndex = tasks.findIndex((t) => t.id === taskIdNum);
|
const taskIndex = tasks.findIndex((t) => t.id === taskIdNum);
|
||||||
if (taskIndex === -1) {
|
if (taskIndex === -1) {
|
||||||
throw new Error(`Task with ID ${taskId} not found in tag '${tag}'`);
|
throw new Error(
|
||||||
|
`Task with ID ${taskId} not found in tag '${currentTag}'`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the task info before removal
|
// Store the task info before removal
|
||||||
@@ -115,7 +116,7 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
tasks.splice(taskIndex, 1);
|
tasks.splice(taskIndex, 1);
|
||||||
|
|
||||||
results.messages.push(
|
results.messages.push(
|
||||||
`Successfully removed task ${taskId} from tag '${tag}'`
|
`Successfully removed task ${taskId} from tag '${currentTag}'`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (innerError) {
|
} catch (innerError) {
|
||||||
@@ -138,7 +139,7 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Update the tasks in the current tag of the full data structure
|
// Update the tasks in the current tag of the full data structure
|
||||||
fullTaggedData[tag].tasks = tasks;
|
fullTaggedData[currentTag].tasks = tasks;
|
||||||
|
|
||||||
// Remove dependencies from all tags
|
// Remove dependencies from all tags
|
||||||
for (const tagName in fullTaggedData) {
|
for (const tagName in fullTaggedData) {
|
||||||
@@ -170,7 +171,7 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save the updated raw data structure
|
// Save the updated raw data structure
|
||||||
writeJSON(tasksPath, fullTaggedData, projectRoot, tag);
|
writeJSON(tasksPath, fullTaggedData, projectRoot, currentTag);
|
||||||
|
|
||||||
// Delete task files AFTER saving tasks.json
|
// Delete task files AFTER saving tasks.json
|
||||||
for (const taskIdNum of tasksToDeleteFiles) {
|
for (const taskIdNum of tasksToDeleteFiles) {
|
||||||
@@ -195,7 +196,7 @@ async function removeTask(tasksPath, taskIds, context = {}) {
|
|||||||
try {
|
try {
|
||||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
||||||
projectRoot,
|
projectRoot,
|
||||||
tag
|
tag: currentTag
|
||||||
});
|
});
|
||||||
results.messages.push('Task files regenerated successfully.');
|
results.messages.push('Task files regenerated successfully.');
|
||||||
} catch (genError) {
|
} catch (genError) {
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import {
|
|||||||
* @param {boolean} [options.includeProjectTree] - Include project file tree
|
* @param {boolean} [options.includeProjectTree] - Include project file tree
|
||||||
* @param {string} [options.detailLevel] - Detail level: 'low', 'medium', 'high'
|
* @param {string} [options.detailLevel] - Detail level: 'low', 'medium', 'high'
|
||||||
* @param {string} [options.projectRoot] - Project root directory
|
* @param {string} [options.projectRoot] - Project root directory
|
||||||
* @param {string} [options.tag] - Tag for the task
|
|
||||||
* @param {boolean} [options.saveToFile] - Whether to save results to file (MCP mode)
|
* @param {boolean} [options.saveToFile] - Whether to save results to file (MCP mode)
|
||||||
* @param {Object} [context] - Execution context
|
* @param {Object} [context] - Execution context
|
||||||
* @param {Object} [context.session] - MCP session object
|
* @param {Object} [context.session] - MCP session object
|
||||||
@@ -60,7 +59,6 @@ async function performResearch(
|
|||||||
includeProjectTree = false,
|
includeProjectTree = false,
|
||||||
detailLevel = 'medium',
|
detailLevel = 'medium',
|
||||||
projectRoot: providedProjectRoot,
|
projectRoot: providedProjectRoot,
|
||||||
tag,
|
|
||||||
saveToFile = false
|
saveToFile = false
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
@@ -103,7 +101,7 @@ async function performResearch(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Initialize context gatherer
|
// Initialize context gatherer
|
||||||
const contextGatherer = new ContextGatherer(projectRoot, tag);
|
const contextGatherer = new ContextGatherer(projectRoot);
|
||||||
|
|
||||||
// Auto-discover relevant tasks using fuzzy search to supplement provided tasks
|
// Auto-discover relevant tasks using fuzzy search to supplement provided tasks
|
||||||
let finalTaskIds = [...taskIds]; // Start with explicitly provided tasks
|
let finalTaskIds = [...taskIds]; // Start with explicitly provided tasks
|
||||||
@@ -116,7 +114,7 @@ async function performResearch(
|
|||||||
'tasks',
|
'tasks',
|
||||||
'tasks.json'
|
'tasks.json'
|
||||||
);
|
);
|
||||||
const tasksData = await readJSON(tasksPath, projectRoot, tag);
|
const tasksData = await readJSON(tasksPath, projectRoot);
|
||||||
|
|
||||||
if (tasksData && tasksData.tasks && tasksData.tasks.length > 0) {
|
if (tasksData && tasksData.tasks && tasksData.tasks.length > 0) {
|
||||||
// Flatten tasks to include subtasks for fuzzy search
|
// Flatten tasks to include subtasks for fuzzy search
|
||||||
@@ -771,7 +769,10 @@ async function handleSaveToTask(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = readJSON(tasksPath, projectRoot, context.tag);
|
// Validate ID exists - use tag from context
|
||||||
|
const { getCurrentTag } = await import('../utils.js');
|
||||||
|
const tag = context.tag || getCurrentTag(projectRoot) || 'master';
|
||||||
|
const data = readJSON(tasksPath, projectRoot, tag);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
console.log(chalk.red('❌ No valid tasks found.'));
|
console.log(chalk.red('❌ No valid tasks found.'));
|
||||||
return;
|
return;
|
||||||
@@ -805,7 +806,7 @@ async function handleSaveToTask(
|
|||||||
trimmedTaskId,
|
trimmedTaskId,
|
||||||
conversationThread,
|
conversationThread,
|
||||||
false, // useResearch = false for simple append
|
false, // useResearch = false for simple append
|
||||||
context,
|
{ ...context, tag },
|
||||||
'text'
|
'text'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -832,7 +833,7 @@ async function handleSaveToTask(
|
|||||||
taskIdNum,
|
taskIdNum,
|
||||||
conversationThread,
|
conversationThread,
|
||||||
false, // useResearch = false for simple append
|
false, // useResearch = false for simple append
|
||||||
context,
|
{ ...context, tag },
|
||||||
'text',
|
'text',
|
||||||
true // appendMode = true
|
true // appendMode = true
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function setResponseLanguage(lang, options = {}) {
|
|||||||
error: {
|
error: {
|
||||||
code: 'CONFIG_MISSING',
|
code: 'CONFIG_MISSING',
|
||||||
message:
|
message:
|
||||||
'The configuration file is missing. Run "task-master init" to create it.'
|
'The configuration file is missing. Run "task-master models --setup" to create it.'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
readJSON,
|
readJSON,
|
||||||
writeJSON,
|
writeJSON,
|
||||||
findTaskById,
|
findTaskById,
|
||||||
|
getCurrentTag,
|
||||||
ensureTagMetadata
|
ensureTagMetadata
|
||||||
} from '../utils.js';
|
} from '../utils.js';
|
||||||
import { displayBanner } from '../ui.js';
|
import { displayBanner } from '../ui.js';
|
||||||
@@ -25,13 +26,16 @@ import {
|
|||||||
* @param {string} taskIdInput - Task ID(s) to update
|
* @param {string} taskIdInput - Task ID(s) to update
|
||||||
* @param {string} newStatus - New status
|
* @param {string} newStatus - New status
|
||||||
* @param {Object} options - Additional options (mcpLog for MCP mode, projectRoot for tag resolution)
|
* @param {Object} options - Additional options (mcpLog for MCP mode, projectRoot for tag resolution)
|
||||||
* @param {string} [options.projectRoot] - Project root path
|
* @param {string} tag - Optional tag to override current tag resolution
|
||||||
* @param {string} [options.tag] - Optional tag to override current tag resolution
|
|
||||||
* @param {string} [options.mcpLog] - MCP logger object
|
|
||||||
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
|
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
|
||||||
*/
|
*/
|
||||||
async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
|
async function setTaskStatus(
|
||||||
const { projectRoot, tag } = options;
|
tasksPath,
|
||||||
|
taskIdInput,
|
||||||
|
newStatus,
|
||||||
|
options = {},
|
||||||
|
tag = null
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
if (!isValidTaskStatus(newStatus)) {
|
if (!isValidTaskStatus(newStatus)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -55,7 +59,7 @@ async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
|
|||||||
log('info', `Reading tasks from ${tasksPath}...`);
|
log('info', `Reading tasks from ${tasksPath}...`);
|
||||||
|
|
||||||
// Read the raw data without tag resolution to preserve tagged structure
|
// Read the raw data without tag resolution to preserve tagged structure
|
||||||
let rawData = readJSON(tasksPath, projectRoot, tag); // No tag parameter
|
let rawData = readJSON(tasksPath, options.projectRoot); // No tag parameter
|
||||||
|
|
||||||
// Handle the case where readJSON returns resolved data with _rawTaggedData
|
// Handle the case where readJSON returns resolved data with _rawTaggedData
|
||||||
if (rawData && rawData._rawTaggedData) {
|
if (rawData && rawData._rawTaggedData) {
|
||||||
@@ -63,17 +67,24 @@ async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
|
|||||||
rawData = rawData._rawTaggedData;
|
rawData = rawData._rawTaggedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the current tag
|
||||||
|
const currentTag = tag || getCurrentTag(options.projectRoot) || 'master';
|
||||||
|
|
||||||
// Ensure the tag exists in the raw data
|
// Ensure the tag exists in the raw data
|
||||||
if (!rawData || !rawData[tag] || !Array.isArray(rawData[tag].tasks)) {
|
if (
|
||||||
|
!rawData ||
|
||||||
|
!rawData[currentTag] ||
|
||||||
|
!Array.isArray(rawData[currentTag].tasks)
|
||||||
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid tasks file or tag "${tag}" not found at ${tasksPath}`
|
`Invalid tasks file or tag "${currentTag}" not found at ${tasksPath}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tasks for the current tag
|
// Get the tasks for the current tag
|
||||||
const data = {
|
const data = {
|
||||||
tasks: rawData[tag].tasks,
|
tasks: rawData[currentTag].tasks,
|
||||||
tag,
|
tag: currentTag,
|
||||||
_rawTaggedData: rawData
|
_rawTaggedData: rawData
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,16 +123,16 @@ async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the raw data structure with the modified tasks
|
// Update the raw data structure with the modified tasks
|
||||||
rawData[tag].tasks = data.tasks;
|
rawData[currentTag].tasks = data.tasks;
|
||||||
|
|
||||||
// Ensure the tag has proper metadata
|
// Ensure the tag has proper metadata
|
||||||
ensureTagMetadata(rawData[tag], {
|
ensureTagMetadata(rawData[currentTag], {
|
||||||
description: `Tasks for ${tag} context`
|
description: `Tasks for ${currentTag} context`
|
||||||
});
|
});
|
||||||
|
|
||||||
// Write the updated raw data back to the file
|
// Write the updated raw data back to the file
|
||||||
// The writeJSON function will automatically filter out _rawTaggedData
|
// The writeJSON function will automatically filter out _rawTaggedData
|
||||||
writeJSON(tasksPath, rawData, projectRoot, tag);
|
writeJSON(tasksPath, rawData, options.projectRoot, currentTag);
|
||||||
|
|
||||||
// Validate dependencies after status update
|
// Validate dependencies after status update
|
||||||
log('info', 'Validating dependencies after status update...');
|
log('info', 'Validating dependencies after status update...');
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import {
|
|||||||
truncate,
|
truncate,
|
||||||
isSilentMode,
|
isSilentMode,
|
||||||
findProjectRoot,
|
findProjectRoot,
|
||||||
flattenTasksWithSubtasks
|
flattenTasksWithSubtasks,
|
||||||
|
getCurrentTag
|
||||||
} 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 } from '../config-manager.js';
|
||||||
@@ -36,7 +37,6 @@ import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
|
|||||||
* @param {Object} [context.session] - Session object from MCP server.
|
* @param {Object} [context.session] - Session object from MCP server.
|
||||||
* @param {Object} [context.mcpLog] - MCP logger object.
|
* @param {Object} [context.mcpLog] - MCP logger object.
|
||||||
* @param {string} [context.projectRoot] - Project root path (needed for AI service key resolution).
|
* @param {string} [context.projectRoot] - Project root path (needed for AI service key resolution).
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
* @param {string} [outputFormat='text'] - Output format ('text' or 'json'). Automatically 'json' if mcpLog is present.
|
* @param {string} [outputFormat='text'] - Output format ('text' or 'json'). Automatically 'json' if mcpLog is present.
|
||||||
* @returns {Promise<Object|null>} - The updated subtask or null if update failed.
|
* @returns {Promise<Object|null>} - The updated subtask or null if update failed.
|
||||||
*/
|
*/
|
||||||
@@ -92,7 +92,10 @@ async function updateSubtaskById(
|
|||||||
throw new Error('Could not determine project root directory');
|
throw new Error('Could not determine project root directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = readJSON(tasksPath, projectRoot, tag);
|
// Determine the tag to use
|
||||||
|
const currentTag = tag || getCurrentTag(projectRoot) || 'master';
|
||||||
|
|
||||||
|
const data = readJSON(tasksPath, projectRoot, currentTag);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`No valid tasks found in ${tasksPath}. The file may be corrupted or have an invalid format.`
|
`No valid tasks found in ${tasksPath}. The file may be corrupted or have an invalid format.`
|
||||||
@@ -139,7 +142,7 @@ async function updateSubtaskById(
|
|||||||
// --- Context Gathering ---
|
// --- Context Gathering ---
|
||||||
let gatheredContext = '';
|
let gatheredContext = '';
|
||||||
try {
|
try {
|
||||||
const contextGatherer = new ContextGatherer(projectRoot, tag);
|
const contextGatherer = new ContextGatherer(projectRoot);
|
||||||
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
||||||
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'update-subtask');
|
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'update-subtask');
|
||||||
const searchQuery = `${parentTask.title} ${subtask.title} ${prompt}`;
|
const searchQuery = `${parentTask.title} ${subtask.title} ${prompt}`;
|
||||||
@@ -328,17 +331,13 @@ async function updateSubtaskById(
|
|||||||
if (outputFormat === 'text' && getDebugFlag(session)) {
|
if (outputFormat === 'text' && getDebugFlag(session)) {
|
||||||
console.log('>>> DEBUG: About to call writeJSON with updated data...');
|
console.log('>>> DEBUG: About to call writeJSON with updated data...');
|
||||||
}
|
}
|
||||||
writeJSON(tasksPath, data, projectRoot, tag);
|
writeJSON(tasksPath, data, projectRoot, currentTag);
|
||||||
if (outputFormat === 'text' && getDebugFlag(session)) {
|
if (outputFormat === 'text' && getDebugFlag(session)) {
|
||||||
console.log('>>> DEBUG: writeJSON call completed.');
|
console.log('>>> DEBUG: writeJSON call completed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
report('success', `Successfully updated subtask ${subtaskId}`);
|
report('success', `Successfully updated subtask ${subtaskId}`);
|
||||||
// Updated function call to make sure if uncommented it will generate the task files for the updated subtask based on the tag
|
// await generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||||
// await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
|
||||||
// tag: tag,
|
|
||||||
// projectRoot: projectRoot
|
|
||||||
// });
|
|
||||||
|
|
||||||
if (outputFormat === 'text') {
|
if (outputFormat === 'text') {
|
||||||
if (loadingIndicator) {
|
if (loadingIndicator) {
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ import {
|
|||||||
truncate,
|
truncate,
|
||||||
isSilentMode,
|
isSilentMode,
|
||||||
flattenTasksWithSubtasks,
|
flattenTasksWithSubtasks,
|
||||||
findProjectRoot
|
findProjectRoot,
|
||||||
|
getCurrentTag
|
||||||
} from '../utils.js';
|
} from '../utils.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -189,45 +190,8 @@ function parseUpdatedTaskFromText(text, expectedTaskId, logFn, isMCP) {
|
|||||||
throw new Error('Parsed AI response is not a valid JSON object.');
|
throw new Error('Parsed AI response is not a valid JSON object.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preprocess the task to ensure subtasks have proper structure
|
|
||||||
const preprocessedTask = {
|
|
||||||
...parsedTask,
|
|
||||||
status: parsedTask.status || 'pending',
|
|
||||||
dependencies: Array.isArray(parsedTask.dependencies)
|
|
||||||
? parsedTask.dependencies
|
|
||||||
: [],
|
|
||||||
details:
|
|
||||||
typeof parsedTask.details === 'string'
|
|
||||||
? parsedTask.details
|
|
||||||
: String(parsedTask.details || ''),
|
|
||||||
testStrategy:
|
|
||||||
typeof parsedTask.testStrategy === 'string'
|
|
||||||
? parsedTask.testStrategy
|
|
||||||
: String(parsedTask.testStrategy || ''),
|
|
||||||
// Ensure subtasks is an array and each subtask has required fields
|
|
||||||
subtasks: Array.isArray(parsedTask.subtasks)
|
|
||||||
? parsedTask.subtasks.map((subtask) => ({
|
|
||||||
...subtask,
|
|
||||||
title: subtask.title || '',
|
|
||||||
description: subtask.description || '',
|
|
||||||
status: subtask.status || 'pending',
|
|
||||||
dependencies: Array.isArray(subtask.dependencies)
|
|
||||||
? subtask.dependencies
|
|
||||||
: [],
|
|
||||||
details:
|
|
||||||
typeof subtask.details === 'string'
|
|
||||||
? subtask.details
|
|
||||||
: String(subtask.details || ''),
|
|
||||||
testStrategy:
|
|
||||||
typeof subtask.testStrategy === 'string'
|
|
||||||
? subtask.testStrategy
|
|
||||||
: String(subtask.testStrategy || '')
|
|
||||||
}))
|
|
||||||
: []
|
|
||||||
};
|
|
||||||
|
|
||||||
// Validate the parsed task object using Zod
|
// Validate the parsed task object using Zod
|
||||||
const validationResult = updatedTaskSchema.safeParse(preprocessedTask);
|
const validationResult = updatedTaskSchema.safeParse(parsedTask);
|
||||||
if (!validationResult.success) {
|
if (!validationResult.success) {
|
||||||
report('error', 'Parsed task object failed Zod validation.');
|
report('error', 'Parsed task object failed Zod validation.');
|
||||||
validationResult.error.errors.forEach((err) => {
|
validationResult.error.errors.forEach((err) => {
|
||||||
@@ -261,7 +225,6 @@ function parseUpdatedTaskFromText(text, expectedTaskId, logFn, isMCP) {
|
|||||||
* @param {Object} [context.session] - Session object from MCP server.
|
* @param {Object} [context.session] - Session object from MCP server.
|
||||||
* @param {Object} [context.mcpLog] - MCP logger object.
|
* @param {Object} [context.mcpLog] - MCP logger object.
|
||||||
* @param {string} [context.projectRoot] - Project root path.
|
* @param {string} [context.projectRoot] - Project root path.
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
* @param {string} [outputFormat='text'] - Output format ('text' or 'json').
|
* @param {string} [outputFormat='text'] - Output format ('text' or 'json').
|
||||||
* @param {boolean} [appendMode=false] - If true, append to details instead of full update.
|
* @param {boolean} [appendMode=false] - If true, append to details instead of full update.
|
||||||
* @returns {Promise<Object|null>} - The updated task or null if update failed.
|
* @returns {Promise<Object|null>} - The updated task or null if update failed.
|
||||||
@@ -320,8 +283,11 @@ async function updateTaskById(
|
|||||||
throw new Error('Could not determine project root directory');
|
throw new Error('Could not determine project root directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the tag to use
|
||||||
|
const currentTag = tag || getCurrentTag(projectRoot) || 'master';
|
||||||
|
|
||||||
// --- Task Loading and Status Check (Keep existing) ---
|
// --- Task Loading and Status Check (Keep existing) ---
|
||||||
const data = readJSON(tasksPath, projectRoot, tag);
|
const data = readJSON(tasksPath, projectRoot, currentTag);
|
||||||
if (!data || !data.tasks)
|
if (!data || !data.tasks)
|
||||||
throw new Error(`No valid tasks found in ${tasksPath}.`);
|
throw new Error(`No valid tasks found in ${tasksPath}.`);
|
||||||
const taskIndex = data.tasks.findIndex((task) => task.id === taskId);
|
const taskIndex = data.tasks.findIndex((task) => task.id === taskId);
|
||||||
@@ -361,7 +327,7 @@ async function updateTaskById(
|
|||||||
// --- Context Gathering ---
|
// --- Context Gathering ---
|
||||||
let gatheredContext = '';
|
let gatheredContext = '';
|
||||||
try {
|
try {
|
||||||
const contextGatherer = new ContextGatherer(projectRoot, tag);
|
const contextGatherer = new ContextGatherer(projectRoot);
|
||||||
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
||||||
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'update-task');
|
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'update-task');
|
||||||
const searchQuery = `${taskToUpdate.title} ${taskToUpdate.description} ${prompt}`;
|
const searchQuery = `${taskToUpdate.title} ${taskToUpdate.description} ${prompt}`;
|
||||||
@@ -556,7 +522,7 @@ async function updateTaskById(
|
|||||||
|
|
||||||
// Write the updated task back to file
|
// Write the updated task back to file
|
||||||
data.tasks[taskIndex] = taskToUpdate;
|
data.tasks[taskIndex] = taskToUpdate;
|
||||||
writeJSON(tasksPath, data, projectRoot, tag);
|
writeJSON(tasksPath, data, projectRoot, currentTag);
|
||||||
report('success', `Successfully appended to task ${taskId}`);
|
report('success', `Successfully appended to task ${taskId}`);
|
||||||
|
|
||||||
// Display success message for CLI
|
// Display success message for CLI
|
||||||
@@ -701,7 +667,7 @@ async function updateTaskById(
|
|||||||
// --- End Update Task Data ---
|
// --- End Update Task Data ---
|
||||||
|
|
||||||
// --- Write File and Generate (Unchanged) ---
|
// --- Write File and Generate (Unchanged) ---
|
||||||
writeJSON(tasksPath, data, projectRoot, tag);
|
writeJSON(tasksPath, data, projectRoot, currentTag);
|
||||||
report('success', `Successfully updated task ${taskId}`);
|
report('success', `Successfully updated task ${taskId}`);
|
||||||
// await generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
// await generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||||
// --- End Write File ---
|
// --- End Write File ---
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import {
|
|||||||
readJSON,
|
readJSON,
|
||||||
writeJSON,
|
writeJSON,
|
||||||
truncate,
|
truncate,
|
||||||
isSilentMode
|
isSilentMode,
|
||||||
|
getCurrentTag
|
||||||
} from '../utils.js';
|
} from '../utils.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -42,39 +43,7 @@ const updatedTaskSchema = z
|
|||||||
subtasks: z.array(z.any()).nullable() // Keep subtasks flexible for now
|
subtasks: z.array(z.any()).nullable() // Keep subtasks flexible for now
|
||||||
})
|
})
|
||||||
.strip(); // Allow potential extra fields during parsing if needed, then validate structure
|
.strip(); // Allow potential extra fields during parsing if needed, then validate structure
|
||||||
|
|
||||||
// Preprocessing schema that adds defaults before validation
|
|
||||||
const preprocessTaskSchema = z.preprocess((task) => {
|
|
||||||
// Ensure task is an object
|
|
||||||
if (typeof task !== 'object' || task === null) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return task with defaults for missing fields
|
|
||||||
return {
|
|
||||||
...task,
|
|
||||||
// Add defaults for required fields if missing
|
|
||||||
id: task.id ?? 0,
|
|
||||||
title: task.title ?? 'Untitled Task',
|
|
||||||
description: task.description ?? '',
|
|
||||||
status: task.status ?? 'pending',
|
|
||||||
dependencies: Array.isArray(task.dependencies) ? task.dependencies : [],
|
|
||||||
// Optional fields - preserve undefined/null distinction
|
|
||||||
priority: task.hasOwnProperty('priority') ? task.priority : null,
|
|
||||||
details: task.hasOwnProperty('details') ? task.details : null,
|
|
||||||
testStrategy: task.hasOwnProperty('testStrategy')
|
|
||||||
? task.testStrategy
|
|
||||||
: null,
|
|
||||||
subtasks: Array.isArray(task.subtasks)
|
|
||||||
? task.subtasks
|
|
||||||
: task.subtasks === null
|
|
||||||
? null
|
|
||||||
: []
|
|
||||||
};
|
|
||||||
}, updatedTaskSchema);
|
|
||||||
|
|
||||||
const updatedTaskArraySchema = z.array(updatedTaskSchema);
|
const updatedTaskArraySchema = z.array(updatedTaskSchema);
|
||||||
const preprocessedTaskArraySchema = z.array(preprocessTaskSchema);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an array of task objects from AI's text response.
|
* Parses an array of task objects from AI's text response.
|
||||||
@@ -227,50 +196,21 @@ function parseUpdatedTasksFromText(text, expectedCount, logFn, isMCP) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log missing fields for debugging before preprocessing
|
const validationResult = updatedTaskArraySchema.safeParse(parsedTasks);
|
||||||
let hasWarnings = false;
|
if (!validationResult.success) {
|
||||||
parsedTasks.forEach((task, index) => {
|
report('error', 'Parsed task array failed Zod validation.');
|
||||||
const missingFields = [];
|
validationResult.error.errors.forEach((err) => {
|
||||||
if (!task.hasOwnProperty('id')) missingFields.push('id');
|
|
||||||
if (!task.hasOwnProperty('status')) missingFields.push('status');
|
|
||||||
if (!task.hasOwnProperty('dependencies'))
|
|
||||||
missingFields.push('dependencies');
|
|
||||||
|
|
||||||
if (missingFields.length > 0) {
|
|
||||||
hasWarnings = true;
|
|
||||||
report(
|
|
||||||
'warn',
|
|
||||||
`Task ${index} is missing fields: ${missingFields.join(', ')} - will use defaults`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasWarnings) {
|
|
||||||
report(
|
|
||||||
'warn',
|
|
||||||
'Some tasks were missing required fields. Applying defaults...'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the preprocessing schema to add defaults and validate
|
|
||||||
const preprocessResult = preprocessedTaskArraySchema.safeParse(parsedTasks);
|
|
||||||
|
|
||||||
if (!preprocessResult.success) {
|
|
||||||
// This should rarely happen now since preprocessing adds defaults
|
|
||||||
report('error', 'Failed to validate task array even after preprocessing.');
|
|
||||||
preprocessResult.error.errors.forEach((err) => {
|
|
||||||
report('error', ` - Path '${err.path.join('.')}': ${err.message}`);
|
report('error', ` - Path '${err.path.join('.')}': ${err.message}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`AI response failed validation: ${preprocessResult.error.message}`
|
`AI response failed task structure validation: ${validationResult.error.message}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
report('info', 'Successfully validated and transformed task structure.');
|
report('info', 'Successfully validated task structure.');
|
||||||
return preprocessResult.data.slice(
|
return validationResult.data.slice(
|
||||||
0,
|
0,
|
||||||
expectedCount || preprocessResult.data.length
|
expectedCount || validationResult.data.length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,8 +223,8 @@ function parseUpdatedTasksFromText(text, expectedCount, logFn, isMCP) {
|
|||||||
* @param {Object} context - Context object containing session and mcpLog.
|
* @param {Object} context - Context object containing session and mcpLog.
|
||||||
* @param {Object} [context.session] - Session object from MCP server.
|
* @param {Object} [context.session] - Session object from MCP server.
|
||||||
* @param {Object} [context.mcpLog] - MCP logger object.
|
* @param {Object} [context.mcpLog] - MCP logger object.
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
* @param {string} [outputFormat='text'] - Output format ('text' or 'json').
|
* @param {string} [outputFormat='text'] - Output format ('text' or 'json').
|
||||||
|
* @param {string} [tag=null] - Tag associated with the tasks.
|
||||||
*/
|
*/
|
||||||
async function updateTasks(
|
async function updateTasks(
|
||||||
tasksPath,
|
tasksPath,
|
||||||
@@ -318,8 +258,11 @@ async function updateTasks(
|
|||||||
throw new Error('Could not determine project root directory');
|
throw new Error('Could not determine project root directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the current tag - prioritize explicit tag, then context.tag, then current tag
|
||||||
|
const currentTag = tag || getCurrentTag(projectRoot) || 'master';
|
||||||
|
|
||||||
// --- Task Loading/Filtering (Updated to pass projectRoot and tag) ---
|
// --- Task Loading/Filtering (Updated to pass projectRoot and tag) ---
|
||||||
const data = readJSON(tasksPath, projectRoot, tag);
|
const data = readJSON(tasksPath, projectRoot, currentTag);
|
||||||
if (!data || !data.tasks)
|
if (!data || !data.tasks)
|
||||||
throw new Error(`No valid tasks found in ${tasksPath}`);
|
throw new Error(`No valid tasks found in ${tasksPath}`);
|
||||||
const tasksToUpdate = data.tasks.filter(
|
const tasksToUpdate = data.tasks.filter(
|
||||||
@@ -338,7 +281,7 @@ async function updateTasks(
|
|||||||
// --- Context Gathering ---
|
// --- Context Gathering ---
|
||||||
let gatheredContext = '';
|
let gatheredContext = '';
|
||||||
try {
|
try {
|
||||||
const contextGatherer = new ContextGatherer(projectRoot, tag);
|
const contextGatherer = new ContextGatherer(projectRoot);
|
||||||
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
const allTasksFlat = flattenTasksWithSubtasks(data.tasks);
|
||||||
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'update');
|
const fuzzySearch = new FuzzyTaskSearch(allTasksFlat, 'update');
|
||||||
const searchResults = fuzzySearch.findRelevantTasks(prompt, {
|
const searchResults = fuzzySearch.findRelevantTasks(prompt, {
|
||||||
@@ -499,17 +442,7 @@ async function updateTasks(
|
|||||||
data.tasks.forEach((task, index) => {
|
data.tasks.forEach((task, index) => {
|
||||||
if (updatedTasksMap.has(task.id)) {
|
if (updatedTasksMap.has(task.id)) {
|
||||||
// Only update if the task was part of the set sent to AI
|
// Only update if the task was part of the set sent to AI
|
||||||
const updatedTask = updatedTasksMap.get(task.id);
|
data.tasks[index] = updatedTasksMap.get(task.id);
|
||||||
// Merge the updated task with the existing one to preserve fields like subtasks
|
|
||||||
data.tasks[index] = {
|
|
||||||
...task, // Keep all existing fields
|
|
||||||
...updatedTask, // Override with updated fields
|
|
||||||
// Ensure subtasks field is preserved if not provided by AI
|
|
||||||
subtasks:
|
|
||||||
updatedTask.subtasks !== undefined
|
|
||||||
? updatedTask.subtasks
|
|
||||||
: task.subtasks
|
|
||||||
};
|
|
||||||
actualUpdateCount++;
|
actualUpdateCount++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -524,7 +457,7 @@ async function updateTasks(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Fix: Pass projectRoot and currentTag to writeJSON
|
// Fix: Pass projectRoot and currentTag to writeJSON
|
||||||
writeJSON(tasksPath, data, projectRoot, tag);
|
writeJSON(tasksPath, data, projectRoot, currentTag);
|
||||||
if (isMCP)
|
if (isMCP)
|
||||||
logFn.info(
|
logFn.info(
|
||||||
`Successfully updated ${actualUpdateCount} tasks in ${tasksPath}`
|
`Successfully updated ${actualUpdateCount} tasks in ${tasksPath}`
|
||||||
|
|||||||
@@ -1197,18 +1197,18 @@ async function displayNextTask(
|
|||||||
* @param {string|number} taskId - The ID of the task to display
|
* @param {string|number} taskId - The ID of the task to display
|
||||||
* @param {string} complexityReportPath - Path to the complexity report file
|
* @param {string} complexityReportPath - Path to the complexity report file
|
||||||
* @param {string} [statusFilter] - Optional status to filter subtasks by
|
* @param {string} [statusFilter] - Optional status to filter subtasks by
|
||||||
* @param {object} context - Context object containing projectRoot and tag
|
* @param {string} tag - Optional tag to override current tag resolution
|
||||||
* @param {string} context.projectRoot - Project root path
|
|
||||||
* @param {string} context.tag - Tag for the task
|
|
||||||
*/
|
*/
|
||||||
async function displayTaskById(
|
async function displayTaskById(
|
||||||
tasksPath,
|
tasksPath,
|
||||||
taskId,
|
taskId,
|
||||||
complexityReportPath = null,
|
complexityReportPath = null,
|
||||||
statusFilter = null,
|
statusFilter = null,
|
||||||
|
tag = null,
|
||||||
context = {}
|
context = {}
|
||||||
) {
|
) {
|
||||||
const { projectRoot, tag } = context;
|
// Extract projectRoot from context
|
||||||
|
const projectRoot = context.projectRoot || null;
|
||||||
|
|
||||||
// Read the tasks file with proper projectRoot for tag resolution
|
// Read the tasks file with proper projectRoot for tag resolution
|
||||||
const data = readJSON(tasksPath, projectRoot, tag);
|
const data = readJSON(tasksPath, projectRoot, tag);
|
||||||
@@ -2251,9 +2251,7 @@ function displayAiUsageSummary(telemetryData, outputType = 'cli') {
|
|||||||
* @param {Array<string>} taskIds - Array of task IDs to display
|
* @param {Array<string>} taskIds - Array of task IDs to display
|
||||||
* @param {string} complexityReportPath - Path to complexity report
|
* @param {string} complexityReportPath - Path to complexity report
|
||||||
* @param {string} statusFilter - Optional status filter for subtasks
|
* @param {string} statusFilter - Optional status filter for subtasks
|
||||||
* @param {Object} context - Context object containing projectRoot and tag
|
* @param {Object} context - Optional context object containing projectRoot and tag
|
||||||
* @param {string} [context.projectRoot] - Project root path
|
|
||||||
* @param {string} [context.tag] - Tag for the task
|
|
||||||
*/
|
*/
|
||||||
async function displayMultipleTasksSummary(
|
async function displayMultipleTasksSummary(
|
||||||
tasksPath,
|
tasksPath,
|
||||||
@@ -2604,6 +2602,7 @@ async function displayMultipleTasksSummary(
|
|||||||
choice.trim(),
|
choice.trim(),
|
||||||
complexityReportPath,
|
complexityReportPath,
|
||||||
statusFilter,
|
statusFilter,
|
||||||
|
tag,
|
||||||
context
|
context
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1190,7 +1190,6 @@ function aggregateTelemetry(telemetryArray, overallCommandName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use TaskMaster.getCurrentTag() instead
|
|
||||||
* Gets the current tag from state.json or falls back to defaultTag from config
|
* Gets the current tag from state.json or falls back to defaultTag from config
|
||||||
* @param {string} projectRoot - The project root directory (required)
|
* @param {string} projectRoot - The project root directory (required)
|
||||||
* @returns {string} The current tag name
|
* @returns {string} The current tag name
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const { encode } = pkg;
|
|||||||
* Context Gatherer class for collecting and formatting context from various sources
|
* Context Gatherer class for collecting and formatting context from various sources
|
||||||
*/
|
*/
|
||||||
export class ContextGatherer {
|
export class ContextGatherer {
|
||||||
constructor(projectRoot, tag) {
|
constructor(projectRoot) {
|
||||||
this.projectRoot = projectRoot;
|
this.projectRoot = projectRoot;
|
||||||
this.tasksPath = path.join(
|
this.tasksPath = path.join(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
@@ -29,13 +29,12 @@ export class ContextGatherer {
|
|||||||
'tasks',
|
'tasks',
|
||||||
'tasks.json'
|
'tasks.json'
|
||||||
);
|
);
|
||||||
this.tag = tag;
|
|
||||||
this.allTasks = this._loadAllTasks();
|
this.allTasks = this._loadAllTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadAllTasks() {
|
_loadAllTasks() {
|
||||||
try {
|
try {
|
||||||
const data = readJSON(this.tasksPath, this.projectRoot, this.tag);
|
const data = readJSON(this.tasksPath, this.projectRoot);
|
||||||
const tasks = data?.tasks || [];
|
const tasks = data?.tasks || [];
|
||||||
return tasks;
|
return tasks;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -959,15 +958,10 @@ export class ContextGatherer {
|
|||||||
/**
|
/**
|
||||||
* Factory function to create a context gatherer instance
|
* Factory function to create a context gatherer instance
|
||||||
* @param {string} projectRoot - Project root directory
|
* @param {string} projectRoot - Project root directory
|
||||||
* @param {string} tag - Tag for the task
|
|
||||||
* @returns {ContextGatherer} Context gatherer instance
|
* @returns {ContextGatherer} Context gatherer instance
|
||||||
* @throws {Error} If tag is not provided
|
|
||||||
*/
|
*/
|
||||||
export function createContextGatherer(projectRoot, tag) {
|
export function createContextGatherer(projectRoot) {
|
||||||
if (!tag) {
|
return new ContextGatherer(projectRoot);
|
||||||
throw new Error('Tag is required');
|
|
||||||
}
|
|
||||||
return new ContextGatherer(projectRoot, tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ContextGatherer;
|
export default ContextGatherer;
|
||||||
|
|||||||
@@ -14,14 +14,6 @@ export class GroqProvider extends BaseAIProvider {
|
|||||||
this.name = 'Groq';
|
this.name = 'Groq';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the environment variable name required for this provider's API key.
|
|
||||||
* @returns {string} The environment variable name for the Groq API key
|
|
||||||
*/
|
|
||||||
getRequiredApiKeyName() {
|
|
||||||
return 'GROQ_API_KEY';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a Groq client instance.
|
* Creates and returns a Groq client instance.
|
||||||
* @param {object} params - Parameters for client initialization
|
* @param {object} params - Parameters for client initialization
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @typedef {'amp' | 'claude' | 'cline' | 'codex' | 'cursor' | 'gemini' | 'kiro' | 'opencode' | 'roo' | 'trae' | 'windsurf' | 'vscode' | 'zed'} RulesProfile
|
* @typedef {'claude' | 'cline' | 'codex' | 'cursor' | 'gemini' | 'roo' | 'trae' | 'windsurf' | 'vscode'} RulesProfile
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,19 +10,15 @@
|
|||||||
*
|
*
|
||||||
* @type {RulesProfile[]}
|
* @type {RulesProfile[]}
|
||||||
* @description Defines possible rule profile sets:
|
* @description Defines possible rule profile sets:
|
||||||
* - amp: Amp Code integration
|
|
||||||
* - claude: Claude Code integration
|
* - claude: Claude Code integration
|
||||||
* - cline: Cline IDE rules
|
* - cline: Cline IDE rules
|
||||||
* - codex: Codex integration
|
* - codex: Codex integration
|
||||||
* - cursor: Cursor IDE rules
|
* - cursor: Cursor IDE rules
|
||||||
* - gemini: Gemini integration
|
* - gemini: Gemini integration
|
||||||
* - kiro: Kiro IDE rules
|
|
||||||
* - opencode: OpenCode integration
|
|
||||||
* - roo: Roo Code IDE rules
|
* - roo: Roo Code IDE rules
|
||||||
* - trae: Trae IDE rules
|
* - trae: Trae IDE rules
|
||||||
* - vscode: VS Code with GitHub Copilot integration
|
* - vscode: VS Code with GitHub Copilot integration
|
||||||
* - windsurf: Windsurf IDE rules
|
* - windsurf: Windsurf IDE rules
|
||||||
* - zed: Zed IDE rules
|
|
||||||
*
|
*
|
||||||
* To add a new rule profile:
|
* To add a new rule profile:
|
||||||
* 1. Add the profile name to this array
|
* 1. Add the profile name to this array
|
||||||
@@ -30,19 +26,15 @@
|
|||||||
* 3. Export it as {profile}Profile in src/profiles/index.js
|
* 3. Export it as {profile}Profile in src/profiles/index.js
|
||||||
*/
|
*/
|
||||||
export const RULE_PROFILES = [
|
export const RULE_PROFILES = [
|
||||||
'amp',
|
|
||||||
'claude',
|
'claude',
|
||||||
'cline',
|
'cline',
|
||||||
'codex',
|
'codex',
|
||||||
'cursor',
|
'cursor',
|
||||||
'gemini',
|
'gemini',
|
||||||
'kiro',
|
|
||||||
'opencode',
|
|
||||||
'roo',
|
'roo',
|
||||||
'trae',
|
'trae',
|
||||||
'vscode',
|
'vscode',
|
||||||
'windsurf',
|
'windsurf'
|
||||||
'zed'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,277 +0,0 @@
|
|||||||
// Amp profile for rule-transformer
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { isSilentMode, log } from '../../scripts/modules/utils.js';
|
|
||||||
import { createProfile } from './base-profile.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform standard MCP config format to Amp format
|
|
||||||
* @param {Object} mcpConfig - Standard MCP configuration object
|
|
||||||
* @returns {Object} - Transformed Amp configuration object
|
|
||||||
*/
|
|
||||||
function transformToAmpFormat(mcpConfig) {
|
|
||||||
const ampConfig = {};
|
|
||||||
|
|
||||||
// Transform mcpServers to amp.mcpServers
|
|
||||||
if (mcpConfig.mcpServers) {
|
|
||||||
ampConfig['amp.mcpServers'] = mcpConfig.mcpServers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preserve any other existing settings
|
|
||||||
for (const [key, value] of Object.entries(mcpConfig)) {
|
|
||||||
if (key !== 'mcpServers') {
|
|
||||||
ampConfig[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ampConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lifecycle functions for Amp profile
|
|
||||||
function onAddRulesProfile(targetDir, assetsDir) {
|
|
||||||
// Handle AGENT.md import for non-destructive integration (Amp uses AGENT.md, copies from AGENTS.md)
|
|
||||||
const sourceFile = path.join(assetsDir, 'AGENTS.md');
|
|
||||||
const userAgentFile = path.join(targetDir, 'AGENT.md');
|
|
||||||
const taskMasterAgentFile = path.join(targetDir, '.taskmaster', 'AGENT.md');
|
|
||||||
const importLine = '@./.taskmaster/AGENT.md';
|
|
||||||
const importSection = `\n## Task Master AI Instructions\n**Import Task Master's development workflow commands and guidelines, treat as if import is in the main AGENT.md file.**\n${importLine}`;
|
|
||||||
|
|
||||||
if (fs.existsSync(sourceFile)) {
|
|
||||||
try {
|
|
||||||
// Ensure .taskmaster directory exists
|
|
||||||
const taskMasterDir = path.join(targetDir, '.taskmaster');
|
|
||||||
if (!fs.existsSync(taskMasterDir)) {
|
|
||||||
fs.mkdirSync(taskMasterDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy Task Master instructions to .taskmaster/AGENT.md
|
|
||||||
fs.copyFileSync(sourceFile, taskMasterAgentFile);
|
|
||||||
log(
|
|
||||||
'debug',
|
|
||||||
`[Amp] Created Task Master instructions at ${taskMasterAgentFile}`
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle user's AGENT.md
|
|
||||||
if (fs.existsSync(userAgentFile)) {
|
|
||||||
// Check if import already exists
|
|
||||||
const content = fs.readFileSync(userAgentFile, 'utf8');
|
|
||||||
if (!content.includes(importLine)) {
|
|
||||||
// Append import section at the end
|
|
||||||
const updatedContent = content.trim() + '\n' + importSection + '\n';
|
|
||||||
fs.writeFileSync(userAgentFile, updatedContent);
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
`[Amp] Added Task Master import to existing ${userAgentFile}`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
`[Amp] Task Master import already present in ${userAgentFile}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Create minimal AGENT.md with the import section
|
|
||||||
const minimalContent = `# Amp Instructions\n${importSection}\n`;
|
|
||||||
fs.writeFileSync(userAgentFile, minimalContent);
|
|
||||||
log('info', `[Amp] Created ${userAgentFile} with Task Master import`);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
log('error', `[Amp] Failed to set up Amp instructions: ${err.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MCP transformation will be handled in onPostConvertRulesProfile
|
|
||||||
}
|
|
||||||
|
|
||||||
function onRemoveRulesProfile(targetDir) {
|
|
||||||
// Clean up AGENT.md import (Amp uses AGENT.md, not AGENTS.md)
|
|
||||||
const userAgentFile = path.join(targetDir, 'AGENT.md');
|
|
||||||
const taskMasterAgentFile = path.join(targetDir, '.taskmaster', 'AGENT.md');
|
|
||||||
const importLine = '@./.taskmaster/AGENT.md';
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Remove Task Master AGENT.md from .taskmaster
|
|
||||||
if (fs.existsSync(taskMasterAgentFile)) {
|
|
||||||
fs.rmSync(taskMasterAgentFile, { force: true });
|
|
||||||
log('debug', `[Amp] Removed ${taskMasterAgentFile}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up import from user's AGENT.md
|
|
||||||
if (fs.existsSync(userAgentFile)) {
|
|
||||||
const content = fs.readFileSync(userAgentFile, 'utf8');
|
|
||||||
const lines = content.split('\n');
|
|
||||||
const filteredLines = [];
|
|
||||||
let skipNextLines = 0;
|
|
||||||
|
|
||||||
// Remove the Task Master section
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
if (skipNextLines > 0) {
|
|
||||||
skipNextLines--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is the start of our Task Master section
|
|
||||||
if (lines[i].includes('## Task Master AI Instructions')) {
|
|
||||||
// Skip this line and the next two lines (bold text and import)
|
|
||||||
skipNextLines = 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also remove standalone import lines (for backward compatibility)
|
|
||||||
if (lines[i].trim() === importLine) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredLines.push(lines[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join back and clean up excessive newlines
|
|
||||||
let updatedContent = filteredLines
|
|
||||||
.join('\n')
|
|
||||||
.replace(/\n{3,}/g, '\n\n')
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
// Check if file only contained our minimal template
|
|
||||||
if (updatedContent === '# Amp Instructions' || updatedContent === '') {
|
|
||||||
// File only contained our import, remove it
|
|
||||||
fs.rmSync(userAgentFile, { force: true });
|
|
||||||
log('debug', `[Amp] Removed empty ${userAgentFile}`);
|
|
||||||
} else {
|
|
||||||
// Write back without the import
|
|
||||||
fs.writeFileSync(userAgentFile, updatedContent + '\n');
|
|
||||||
log('debug', `[Amp] Removed Task Master import from ${userAgentFile}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
log('error', `[Amp] Failed to remove Amp instructions: ${err.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MCP Removal: Remove amp.mcpServers section
|
|
||||||
const mcpConfigPath = path.join(targetDir, '.vscode', 'settings.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(mcpConfigPath)) {
|
|
||||||
log('debug', '[Amp] No .vscode/settings.json found to clean up');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the current config
|
|
||||||
const configContent = fs.readFileSync(mcpConfigPath, 'utf8');
|
|
||||||
const config = JSON.parse(configContent);
|
|
||||||
|
|
||||||
// Check if it has the amp.mcpServers section and task-master-ai server
|
|
||||||
if (
|
|
||||||
config['amp.mcpServers'] &&
|
|
||||||
config['amp.mcpServers']['task-master-ai']
|
|
||||||
) {
|
|
||||||
// Remove task-master-ai server
|
|
||||||
delete config['amp.mcpServers']['task-master-ai'];
|
|
||||||
|
|
||||||
// Check if there are other MCP servers in amp.mcpServers
|
|
||||||
const remainingServers = Object.keys(config['amp.mcpServers']);
|
|
||||||
|
|
||||||
if (remainingServers.length === 0) {
|
|
||||||
// No other servers, remove entire amp.mcpServers section
|
|
||||||
delete config['amp.mcpServers'];
|
|
||||||
log('debug', '[Amp] Removed empty amp.mcpServers section');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if config is now empty
|
|
||||||
const remainingKeys = Object.keys(config);
|
|
||||||
|
|
||||||
if (remainingKeys.length === 0) {
|
|
||||||
// Config is empty, remove entire file
|
|
||||||
fs.rmSync(mcpConfigPath, { force: true });
|
|
||||||
log('info', '[Amp] Removed empty settings.json file');
|
|
||||||
|
|
||||||
// Check if .vscode directory is empty
|
|
||||||
const vscodeDirPath = path.join(targetDir, '.vscode');
|
|
||||||
if (fs.existsSync(vscodeDirPath)) {
|
|
||||||
const remainingContents = fs.readdirSync(vscodeDirPath);
|
|
||||||
if (remainingContents.length === 0) {
|
|
||||||
fs.rmSync(vscodeDirPath, { recursive: true, force: true });
|
|
||||||
log('debug', '[Amp] Removed empty .vscode directory');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Write back the modified config
|
|
||||||
fs.writeFileSync(
|
|
||||||
mcpConfigPath,
|
|
||||||
JSON.stringify(config, null, '\t') + '\n'
|
|
||||||
);
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[Amp] Removed TaskMaster from settings.json, preserved other configurations'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log('debug', '[Amp] TaskMaster not found in amp.mcpServers');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
log('error', `[Amp] Failed to clean up settings.json: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
|
||||||
// Handle AGENT.md setup (same as onAddRulesProfile)
|
|
||||||
onAddRulesProfile(targetDir, assetsDir);
|
|
||||||
|
|
||||||
// Transform MCP config to Amp format
|
|
||||||
const mcpConfigPath = path.join(targetDir, '.vscode', 'settings.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(mcpConfigPath)) {
|
|
||||||
log('debug', '[Amp] No .vscode/settings.json found to transform');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the generated standard MCP config
|
|
||||||
const mcpConfigContent = fs.readFileSync(mcpConfigPath, 'utf8');
|
|
||||||
const mcpConfig = JSON.parse(mcpConfigContent);
|
|
||||||
|
|
||||||
// Check if it's already in Amp format (has amp.mcpServers)
|
|
||||||
if (mcpConfig['amp.mcpServers']) {
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[Amp] settings.json already in Amp format, skipping transformation'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform to Amp format
|
|
||||||
const ampConfig = transformToAmpFormat(mcpConfig);
|
|
||||||
|
|
||||||
// Write back the transformed config with proper formatting
|
|
||||||
fs.writeFileSync(
|
|
||||||
mcpConfigPath,
|
|
||||||
JSON.stringify(ampConfig, null, '\t') + '\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
log('info', '[Amp] Transformed settings.json to Amp format');
|
|
||||||
log('debug', '[Amp] Renamed mcpServers to amp.mcpServers');
|
|
||||||
} catch (error) {
|
|
||||||
log('error', `[Amp] Failed to transform settings.json: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and export amp profile using the base factory
|
|
||||||
export const ampProfile = createProfile({
|
|
||||||
name: 'amp',
|
|
||||||
displayName: 'Amp',
|
|
||||||
url: 'ampcode.com',
|
|
||||||
docsUrl: 'ampcode.com/manual',
|
|
||||||
profileDir: '.vscode',
|
|
||||||
rulesDir: '.',
|
|
||||||
mcpConfig: true,
|
|
||||||
mcpConfigName: 'settings.json',
|
|
||||||
includeDefaultRules: false,
|
|
||||||
fileMap: {
|
|
||||||
'AGENTS.md': '.taskmaster/AGENT.md'
|
|
||||||
},
|
|
||||||
onAdd: onAddRulesProfile,
|
|
||||||
onRemove: onRemoveRulesProfile,
|
|
||||||
onPostConvert: onPostConvertRulesProfile
|
|
||||||
});
|
|
||||||
|
|
||||||
// Export lifecycle functions separately to avoid naming conflicts
|
|
||||||
export { onAddRulesProfile, onRemoveRulesProfile, onPostConvertRulesProfile };
|
|
||||||
@@ -46,9 +46,7 @@ export function createProfile(editorConfig) {
|
|||||||
onPostConvert
|
onPostConvert
|
||||||
} = editorConfig;
|
} = editorConfig;
|
||||||
|
|
||||||
const mcpConfigPath = mcpConfigName
|
const mcpConfigPath = mcpConfigName ? `${profileDir}/${mcpConfigName}` : null;
|
||||||
? path.join(profileDir, mcpConfigName)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Standard file mapping with custom overrides
|
// Standard file mapping with custom overrides
|
||||||
// Use taskmaster subdirectory only if profile supports it
|
// Use taskmaster subdirectory only if profile supports it
|
||||||
|
|||||||
@@ -197,73 +197,9 @@ function onRemoveRulesProfile(targetDir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform standard MCP config format to Claude format
|
|
||||||
* @param {Object} mcpConfig - Standard MCP configuration object
|
|
||||||
* @returns {Object} - Transformed Claude configuration object
|
|
||||||
*/
|
|
||||||
function transformToClaudeFormat(mcpConfig) {
|
|
||||||
const claudeConfig = {};
|
|
||||||
|
|
||||||
// Transform mcpServers to servers (keeping the same structure but adding type)
|
|
||||||
if (mcpConfig.mcpServers) {
|
|
||||||
claudeConfig.mcpServers = {};
|
|
||||||
|
|
||||||
for (const [serverName, serverConfig] of Object.entries(
|
|
||||||
mcpConfig.mcpServers
|
|
||||||
)) {
|
|
||||||
// Transform server configuration with type as first key
|
|
||||||
const reorderedServer = {};
|
|
||||||
|
|
||||||
// Add type: "stdio" as the first key
|
|
||||||
reorderedServer.type = 'stdio';
|
|
||||||
|
|
||||||
// Then add the rest of the properties in order
|
|
||||||
if (serverConfig.command) reorderedServer.command = serverConfig.command;
|
|
||||||
if (serverConfig.args) reorderedServer.args = serverConfig.args;
|
|
||||||
if (serverConfig.env) reorderedServer.env = serverConfig.env;
|
|
||||||
|
|
||||||
// Add any other properties that might exist
|
|
||||||
Object.keys(serverConfig).forEach((key) => {
|
|
||||||
if (!['command', 'args', 'env', 'type'].includes(key)) {
|
|
||||||
reorderedServer[key] = serverConfig[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
claudeConfig.mcpServers[serverName] = reorderedServer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return claudeConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
||||||
// For Claude, post-convert is the same as add since we don't transform rules
|
// For Claude, post-convert is the same as add since we don't transform rules
|
||||||
onAddRulesProfile(targetDir, assetsDir);
|
onAddRulesProfile(targetDir, assetsDir);
|
||||||
|
|
||||||
// Transform MCP configuration to Claude format
|
|
||||||
const mcpConfigPath = path.join(targetDir, '.mcp.json');
|
|
||||||
if (fs.existsSync(mcpConfigPath)) {
|
|
||||||
try {
|
|
||||||
const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
|
|
||||||
const claudeConfig = transformToClaudeFormat(mcpConfig);
|
|
||||||
|
|
||||||
// Write back the transformed configuration
|
|
||||||
fs.writeFileSync(
|
|
||||||
mcpConfigPath,
|
|
||||||
JSON.stringify(claudeConfig, null, '\t') + '\n'
|
|
||||||
);
|
|
||||||
log(
|
|
||||||
'debug',
|
|
||||||
`[Claude] Transformed MCP configuration to Claude format at ${mcpConfigPath}`
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
log(
|
|
||||||
'error',
|
|
||||||
`[Claude] Failed to transform MCP configuration: ${err.message}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and export claude profile using the base factory
|
// Create and export claude profile using the base factory
|
||||||
@@ -274,7 +210,8 @@ export const claudeProfile = createProfile({
|
|||||||
docsUrl: 'docs.anthropic.com/en/docs/claude-code',
|
docsUrl: 'docs.anthropic.com/en/docs/claude-code',
|
||||||
profileDir: '.', // Root directory
|
profileDir: '.', // Root directory
|
||||||
rulesDir: '.', // No specific rules directory needed
|
rulesDir: '.', // No specific rules directory needed
|
||||||
mcpConfigName: '.mcp.json', // Place MCP config in project root
|
mcpConfig: false,
|
||||||
|
mcpConfigName: null,
|
||||||
includeDefaultRules: false,
|
includeDefaultRules: false,
|
||||||
fileMap: {
|
fileMap: {
|
||||||
'AGENTS.md': '.taskmaster/CLAUDE.md'
|
'AGENTS.md': '.taskmaster/CLAUDE.md'
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
// Profile exports for centralized importing
|
// Profile exports for centralized importing
|
||||||
export { ampProfile } from './amp.js';
|
|
||||||
export { claudeProfile } from './claude.js';
|
export { claudeProfile } from './claude.js';
|
||||||
export { clineProfile } from './cline.js';
|
export { clineProfile } from './cline.js';
|
||||||
export { codexProfile } from './codex.js';
|
export { codexProfile } from './codex.js';
|
||||||
export { cursorProfile } from './cursor.js';
|
export { cursorProfile } from './cursor.js';
|
||||||
export { geminiProfile } from './gemini.js';
|
export { geminiProfile } from './gemini.js';
|
||||||
export { kiroProfile } from './kiro.js';
|
|
||||||
export { opencodeProfile } from './opencode.js';
|
|
||||||
export { rooProfile } from './roo.js';
|
export { rooProfile } from './roo.js';
|
||||||
export { traeProfile } from './trae.js';
|
export { traeProfile } from './trae.js';
|
||||||
export { vscodeProfile } from './vscode.js';
|
export { vscodeProfile } from './vscode.js';
|
||||||
export { windsurfProfile } from './windsurf.js';
|
export { windsurfProfile } from './windsurf.js';
|
||||||
export { zedProfile } from './zed.js';
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
// Kiro profile for rule-transformer
|
|
||||||
import { createProfile } from './base-profile.js';
|
|
||||||
|
|
||||||
// Create and export kiro profile using the base factory
|
|
||||||
export const kiroProfile = createProfile({
|
|
||||||
name: 'kiro',
|
|
||||||
displayName: 'Kiro',
|
|
||||||
url: 'kiro.dev',
|
|
||||||
docsUrl: 'kiro.dev/docs',
|
|
||||||
profileDir: '.kiro',
|
|
||||||
rulesDir: '.kiro/steering', // Kiro rules location (full path)
|
|
||||||
mcpConfig: true,
|
|
||||||
mcpConfigName: 'settings/mcp.json', // Create directly in settings subdirectory
|
|
||||||
includeDefaultRules: true, // Include default rules to get all the standard files
|
|
||||||
targetExtension: '.md',
|
|
||||||
fileMap: {
|
|
||||||
// Override specific mappings - the base profile will create:
|
|
||||||
// 'rules/cursor_rules.mdc': 'kiro_rules.md'
|
|
||||||
// 'rules/dev_workflow.mdc': 'dev_workflow.md'
|
|
||||||
// 'rules/self_improve.mdc': 'self_improve.md'
|
|
||||||
// 'rules/taskmaster.mdc': 'taskmaster.md'
|
|
||||||
// We can add additional custom mappings here if needed
|
|
||||||
},
|
|
||||||
customReplacements: [
|
|
||||||
// Core Kiro directory structure changes
|
|
||||||
{ from: /\.cursor\/rules/g, to: '.kiro/steering' },
|
|
||||||
{ from: /\.cursor\/mcp\.json/g, to: '.kiro/settings/mcp.json' },
|
|
||||||
|
|
||||||
// Fix any remaining kiro/rules references that might be created during transformation
|
|
||||||
{ from: /\.kiro\/rules/g, to: '.kiro/steering' },
|
|
||||||
|
|
||||||
// Essential markdown link transformations for Kiro structure
|
|
||||||
{
|
|
||||||
from: /\[(.+?)\]\(mdc:\.cursor\/rules\/(.+?)\.mdc\)/g,
|
|
||||||
to: '[$1](.kiro/steering/$2.md)'
|
|
||||||
},
|
|
||||||
|
|
||||||
// Kiro specific terminology
|
|
||||||
{ from: /rules directory/g, to: 'steering directory' },
|
|
||||||
{ from: /cursor rules/gi, to: 'Kiro steering files' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
// Opencode profile for rule-transformer
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { log } from '../../scripts/modules/utils.js';
|
|
||||||
import { createProfile } from './base-profile.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform standard MCP config format to OpenCode format
|
|
||||||
* @param {Object} mcpConfig - Standard MCP configuration object
|
|
||||||
* @returns {Object} - Transformed OpenCode configuration object
|
|
||||||
*/
|
|
||||||
function transformToOpenCodeFormat(mcpConfig) {
|
|
||||||
const openCodeConfig = {
|
|
||||||
$schema: 'https://opencode.ai/config.json'
|
|
||||||
};
|
|
||||||
|
|
||||||
// Transform mcpServers to mcp
|
|
||||||
if (mcpConfig.mcpServers) {
|
|
||||||
openCodeConfig.mcp = {};
|
|
||||||
|
|
||||||
for (const [serverName, serverConfig] of Object.entries(
|
|
||||||
mcpConfig.mcpServers
|
|
||||||
)) {
|
|
||||||
// Transform server configuration
|
|
||||||
const transformedServer = {
|
|
||||||
type: 'local'
|
|
||||||
};
|
|
||||||
|
|
||||||
// Combine command and args into single command array
|
|
||||||
if (serverConfig.command && serverConfig.args) {
|
|
||||||
transformedServer.command = [
|
|
||||||
serverConfig.command,
|
|
||||||
...serverConfig.args
|
|
||||||
];
|
|
||||||
} else if (serverConfig.command) {
|
|
||||||
transformedServer.command = [serverConfig.command];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add enabled flag
|
|
||||||
transformedServer.enabled = true;
|
|
||||||
|
|
||||||
// Transform env to environment
|
|
||||||
if (serverConfig.env) {
|
|
||||||
transformedServer.environment = serverConfig.env;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update with transformed config
|
|
||||||
openCodeConfig.mcp[serverName] = transformedServer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return openCodeConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifecycle function called after MCP config generation to transform to OpenCode format
|
|
||||||
* @param {string} targetDir - Target project directory
|
|
||||||
* @param {string} assetsDir - Assets directory (unused for OpenCode)
|
|
||||||
*/
|
|
||||||
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
|
||||||
const openCodeConfigPath = path.join(targetDir, 'opencode.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(openCodeConfigPath)) {
|
|
||||||
log('debug', '[OpenCode] No opencode.json found to transform');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the generated standard MCP config
|
|
||||||
const mcpConfigContent = fs.readFileSync(openCodeConfigPath, 'utf8');
|
|
||||||
const mcpConfig = JSON.parse(mcpConfigContent);
|
|
||||||
|
|
||||||
// Check if it's already in OpenCode format (has $schema)
|
|
||||||
if (mcpConfig.$schema) {
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[OpenCode] opencode.json already in OpenCode format, skipping transformation'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform to OpenCode format
|
|
||||||
const openCodeConfig = transformToOpenCodeFormat(mcpConfig);
|
|
||||||
|
|
||||||
// Write back the transformed config with proper formatting
|
|
||||||
fs.writeFileSync(
|
|
||||||
openCodeConfigPath,
|
|
||||||
JSON.stringify(openCodeConfig, null, 2) + '\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
log('info', '[OpenCode] Transformed opencode.json to OpenCode format');
|
|
||||||
log(
|
|
||||||
'debug',
|
|
||||||
`[OpenCode] Added schema, renamed mcpServers->mcp, combined command+args, added type/enabled, renamed env->environment`
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
log(
|
|
||||||
'error',
|
|
||||||
`[OpenCode] Failed to transform opencode.json: ${error.message}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifecycle function called when removing OpenCode profile
|
|
||||||
* @param {string} targetDir - Target project directory
|
|
||||||
*/
|
|
||||||
function onRemoveRulesProfile(targetDir) {
|
|
||||||
const openCodeConfigPath = path.join(targetDir, 'opencode.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(openCodeConfigPath)) {
|
|
||||||
log('debug', '[OpenCode] No opencode.json found to clean up');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the current config
|
|
||||||
const configContent = fs.readFileSync(openCodeConfigPath, 'utf8');
|
|
||||||
const config = JSON.parse(configContent);
|
|
||||||
|
|
||||||
// Check if it has the mcp section and taskmaster-ai server
|
|
||||||
if (config.mcp && config.mcp['taskmaster-ai']) {
|
|
||||||
// Remove taskmaster-ai server
|
|
||||||
delete config.mcp['taskmaster-ai'];
|
|
||||||
|
|
||||||
// Check if there are other MCP servers
|
|
||||||
const remainingServers = Object.keys(config.mcp);
|
|
||||||
|
|
||||||
if (remainingServers.length === 0) {
|
|
||||||
// No other servers, remove entire mcp section
|
|
||||||
delete config.mcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if config is now empty (only has $schema)
|
|
||||||
const remainingKeys = Object.keys(config).filter(
|
|
||||||
(key) => key !== '$schema'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (remainingKeys.length === 0) {
|
|
||||||
// Config only has schema left, remove entire file
|
|
||||||
fs.rmSync(openCodeConfigPath, { force: true });
|
|
||||||
log('info', '[OpenCode] Removed empty opencode.json file');
|
|
||||||
} else {
|
|
||||||
// Write back the modified config
|
|
||||||
fs.writeFileSync(
|
|
||||||
openCodeConfigPath,
|
|
||||||
JSON.stringify(config, null, 2) + '\n'
|
|
||||||
);
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[OpenCode] Removed TaskMaster from opencode.json, preserved other configurations'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log('debug', '[OpenCode] TaskMaster not found in opencode.json');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
log(
|
|
||||||
'error',
|
|
||||||
`[OpenCode] Failed to clean up opencode.json: ${error.message}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and export opencode profile using the base factory
|
|
||||||
export const opencodeProfile = createProfile({
|
|
||||||
name: 'opencode',
|
|
||||||
displayName: 'OpenCode',
|
|
||||||
url: 'opencode.ai',
|
|
||||||
docsUrl: 'opencode.ai/docs/',
|
|
||||||
profileDir: '.', // Root directory
|
|
||||||
rulesDir: '.', // Root directory for AGENTS.md
|
|
||||||
mcpConfigName: 'opencode.json', // Override default 'mcp.json'
|
|
||||||
includeDefaultRules: false,
|
|
||||||
fileMap: {
|
|
||||||
'AGENTS.md': 'AGENTS.md'
|
|
||||||
},
|
|
||||||
onPostConvert: onPostConvertRulesProfile,
|
|
||||||
onRemove: onRemoveRulesProfile
|
|
||||||
});
|
|
||||||
|
|
||||||
// Export lifecycle functions separately to avoid naming conflicts
|
|
||||||
export { onPostConvertRulesProfile, onRemoveRulesProfile };
|
|
||||||
@@ -1,162 +1,6 @@
|
|||||||
// VS Code conversion profile for rule-transformer
|
// VS Code conversion profile for rule-transformer
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { log } from '../../scripts/modules/utils.js';
|
|
||||||
import { createProfile, COMMON_TOOL_MAPPINGS } from './base-profile.js';
|
import { createProfile, COMMON_TOOL_MAPPINGS } from './base-profile.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform standard MCP config format to VS Code format
|
|
||||||
* @param {Object} mcpConfig - Standard MCP configuration object
|
|
||||||
* @returns {Object} - Transformed VS Code configuration object
|
|
||||||
*/
|
|
||||||
function transformToVSCodeFormat(mcpConfig) {
|
|
||||||
const vscodeConfig = {};
|
|
||||||
|
|
||||||
// Transform mcpServers to servers
|
|
||||||
if (mcpConfig.mcpServers) {
|
|
||||||
vscodeConfig.servers = {};
|
|
||||||
|
|
||||||
for (const [serverName, serverConfig] of Object.entries(
|
|
||||||
mcpConfig.mcpServers
|
|
||||||
)) {
|
|
||||||
// Transform server configuration
|
|
||||||
const transformedServer = {
|
|
||||||
...serverConfig
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add type: "stdio" after the env block
|
|
||||||
if (transformedServer.env) {
|
|
||||||
// Reorder properties: keep command, args, env, then add type
|
|
||||||
const reorderedServer = {};
|
|
||||||
if (transformedServer.command)
|
|
||||||
reorderedServer.command = transformedServer.command;
|
|
||||||
if (transformedServer.args)
|
|
||||||
reorderedServer.args = transformedServer.args;
|
|
||||||
if (transformedServer.env) reorderedServer.env = transformedServer.env;
|
|
||||||
reorderedServer.type = 'stdio';
|
|
||||||
|
|
||||||
// Add any other properties that might exist
|
|
||||||
Object.keys(transformedServer).forEach((key) => {
|
|
||||||
if (!['command', 'args', 'env', 'type'].includes(key)) {
|
|
||||||
reorderedServer[key] = transformedServer[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
vscodeConfig.servers[serverName] = reorderedServer;
|
|
||||||
} else {
|
|
||||||
// If no env block, just add type at the end
|
|
||||||
transformedServer.type = 'stdio';
|
|
||||||
vscodeConfig.servers[serverName] = transformedServer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vscodeConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifecycle function called after MCP config generation to transform to VS Code format
|
|
||||||
* @param {string} targetDir - Target project directory
|
|
||||||
* @param {string} assetsDir - Assets directory (unused for VS Code)
|
|
||||||
*/
|
|
||||||
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
|
||||||
const vscodeConfigPath = path.join(targetDir, '.vscode', 'mcp.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(vscodeConfigPath)) {
|
|
||||||
log('debug', '[VS Code] No .vscode/mcp.json found to transform');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the generated standard MCP config
|
|
||||||
const mcpConfigContent = fs.readFileSync(vscodeConfigPath, 'utf8');
|
|
||||||
const mcpConfig = JSON.parse(mcpConfigContent);
|
|
||||||
|
|
||||||
// Check if it's already in VS Code format (has servers instead of mcpServers)
|
|
||||||
if (mcpConfig.servers) {
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[VS Code] mcp.json already in VS Code format, skipping transformation'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform to VS Code format
|
|
||||||
const vscodeConfig = transformToVSCodeFormat(mcpConfig);
|
|
||||||
|
|
||||||
// Write back the transformed config with proper formatting
|
|
||||||
fs.writeFileSync(
|
|
||||||
vscodeConfigPath,
|
|
||||||
JSON.stringify(vscodeConfig, null, 2) + '\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
log('info', '[VS Code] Transformed mcp.json to VS Code format');
|
|
||||||
log('debug', `[VS Code] Renamed mcpServers->servers, added type: "stdio"`);
|
|
||||||
} catch (error) {
|
|
||||||
log('error', `[VS Code] Failed to transform mcp.json: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifecycle function called when removing VS Code profile
|
|
||||||
* @param {string} targetDir - Target project directory
|
|
||||||
*/
|
|
||||||
function onRemoveRulesProfile(targetDir) {
|
|
||||||
const vscodeConfigPath = path.join(targetDir, '.vscode', 'mcp.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(vscodeConfigPath)) {
|
|
||||||
log('debug', '[VS Code] No .vscode/mcp.json found to clean up');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the current config
|
|
||||||
const configContent = fs.readFileSync(vscodeConfigPath, 'utf8');
|
|
||||||
const config = JSON.parse(configContent);
|
|
||||||
|
|
||||||
// Check if it has the servers section and task-master-ai server
|
|
||||||
if (config.servers && config.servers['task-master-ai']) {
|
|
||||||
// Remove task-master-ai server
|
|
||||||
delete config.servers['task-master-ai'];
|
|
||||||
|
|
||||||
// Check if there are other MCP servers
|
|
||||||
const remainingServers = Object.keys(config.servers);
|
|
||||||
|
|
||||||
if (remainingServers.length === 0) {
|
|
||||||
// No other servers, remove entire file
|
|
||||||
fs.rmSync(vscodeConfigPath, { force: true });
|
|
||||||
log('info', '[VS Code] Removed empty mcp.json file');
|
|
||||||
|
|
||||||
// Also remove .vscode directory if it's empty
|
|
||||||
const vscodeDir = path.dirname(vscodeConfigPath);
|
|
||||||
try {
|
|
||||||
const dirContents = fs.readdirSync(vscodeDir);
|
|
||||||
if (dirContents.length === 0) {
|
|
||||||
fs.rmSync(vscodeDir, { recursive: true, force: true });
|
|
||||||
log('debug', '[VS Code] Removed empty .vscode directory');
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// Directory might not be empty or might not exist, that's fine
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Write back the modified config
|
|
||||||
fs.writeFileSync(
|
|
||||||
vscodeConfigPath,
|
|
||||||
JSON.stringify(config, null, 2) + '\n'
|
|
||||||
);
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[VS Code] Removed TaskMaster from mcp.json, preserved other configurations'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log('debug', '[VS Code] TaskMaster not found in mcp.json');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
log('error', `[VS Code] Failed to clean up mcp.json: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and export vscode profile using the base factory
|
// Create and export vscode profile using the base factory
|
||||||
export const vscodeProfile = createProfile({
|
export const vscodeProfile = createProfile({
|
||||||
name: 'vscode',
|
name: 'vscode',
|
||||||
@@ -164,8 +8,6 @@ export const vscodeProfile = createProfile({
|
|||||||
url: 'code.visualstudio.com',
|
url: 'code.visualstudio.com',
|
||||||
docsUrl: 'code.visualstudio.com/docs',
|
docsUrl: 'code.visualstudio.com/docs',
|
||||||
rulesDir: '.github/instructions', // VS Code instructions location
|
rulesDir: '.github/instructions', // VS Code instructions location
|
||||||
profileDir: '.vscode', // VS Code configuration directory
|
|
||||||
mcpConfigName: 'mcp.json', // VS Code uses mcp.json in .vscode directory
|
|
||||||
customReplacements: [
|
customReplacements: [
|
||||||
// Core VS Code directory structure changes
|
// Core VS Code directory structure changes
|
||||||
{ from: /\.cursor\/rules/g, to: '.github/instructions' },
|
{ from: /\.cursor\/rules/g, to: '.github/instructions' },
|
||||||
@@ -186,10 +28,5 @@ export const vscodeProfile = createProfile({
|
|||||||
// VS Code specific terminology
|
// VS Code specific terminology
|
||||||
{ from: /rules directory/g, to: 'instructions directory' },
|
{ from: /rules directory/g, to: 'instructions directory' },
|
||||||
{ from: /cursor rules/gi, to: 'VS Code instructions' }
|
{ from: /cursor rules/gi, to: 'VS Code instructions' }
|
||||||
],
|
]
|
||||||
onPostConvert: onPostConvertRulesProfile,
|
|
||||||
onRemove: onRemoveRulesProfile
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export lifecycle functions separately to avoid naming conflicts
|
|
||||||
export { onPostConvertRulesProfile, onRemoveRulesProfile };
|
|
||||||
|
|||||||
@@ -1,178 +0,0 @@
|
|||||||
// Zed profile for rule-transformer
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { isSilentMode, log } from '../../scripts/modules/utils.js';
|
|
||||||
import { createProfile } from './base-profile.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform standard MCP config format to Zed format
|
|
||||||
* @param {Object} mcpConfig - Standard MCP configuration object
|
|
||||||
* @returns {Object} - Transformed Zed configuration object
|
|
||||||
*/
|
|
||||||
function transformToZedFormat(mcpConfig) {
|
|
||||||
const zedConfig = {};
|
|
||||||
|
|
||||||
// Transform mcpServers to context_servers
|
|
||||||
if (mcpConfig.mcpServers) {
|
|
||||||
zedConfig['context_servers'] = mcpConfig.mcpServers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preserve any other existing settings
|
|
||||||
for (const [key, value] of Object.entries(mcpConfig)) {
|
|
||||||
if (key !== 'mcpServers') {
|
|
||||||
zedConfig[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return zedConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lifecycle functions for Zed profile
|
|
||||||
function onAddRulesProfile(targetDir, assetsDir) {
|
|
||||||
// MCP transformation will be handled in onPostConvertRulesProfile
|
|
||||||
// File copying is handled by the base profile via fileMap
|
|
||||||
}
|
|
||||||
|
|
||||||
function onRemoveRulesProfile(targetDir) {
|
|
||||||
// Clean up .rules (Zed uses .rules directly in root)
|
|
||||||
const userRulesFile = path.join(targetDir, '.rules');
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Remove Task Master .rules
|
|
||||||
if (fs.existsSync(userRulesFile)) {
|
|
||||||
fs.rmSync(userRulesFile, { force: true });
|
|
||||||
log('debug', `[Zed] Removed ${userRulesFile}`);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
log('error', `[Zed] Failed to remove Zed instructions: ${err.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MCP Removal: Remove context_servers section
|
|
||||||
const mcpConfigPath = path.join(targetDir, '.zed', 'settings.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(mcpConfigPath)) {
|
|
||||||
log('debug', '[Zed] No .zed/settings.json found to clean up');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the current config
|
|
||||||
const configContent = fs.readFileSync(mcpConfigPath, 'utf8');
|
|
||||||
const config = JSON.parse(configContent);
|
|
||||||
|
|
||||||
// Check if it has the context_servers section and task-master-ai server
|
|
||||||
if (
|
|
||||||
config['context_servers'] &&
|
|
||||||
config['context_servers']['task-master-ai']
|
|
||||||
) {
|
|
||||||
// Remove task-master-ai server
|
|
||||||
delete config['context_servers']['task-master-ai'];
|
|
||||||
|
|
||||||
// Check if there are other MCP servers in context_servers
|
|
||||||
const remainingServers = Object.keys(config['context_servers']);
|
|
||||||
|
|
||||||
if (remainingServers.length === 0) {
|
|
||||||
// No other servers, remove entire context_servers section
|
|
||||||
delete config['context_servers'];
|
|
||||||
log('debug', '[Zed] Removed empty context_servers section');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if config is now empty
|
|
||||||
const remainingKeys = Object.keys(config);
|
|
||||||
|
|
||||||
if (remainingKeys.length === 0) {
|
|
||||||
// Config is empty, remove entire file
|
|
||||||
fs.rmSync(mcpConfigPath, { force: true });
|
|
||||||
log('info', '[Zed] Removed empty settings.json file');
|
|
||||||
|
|
||||||
// Check if .zed directory is empty
|
|
||||||
const zedDirPath = path.join(targetDir, '.zed');
|
|
||||||
if (fs.existsSync(zedDirPath)) {
|
|
||||||
const remainingContents = fs.readdirSync(zedDirPath);
|
|
||||||
if (remainingContents.length === 0) {
|
|
||||||
fs.rmSync(zedDirPath, { recursive: true, force: true });
|
|
||||||
log('debug', '[Zed] Removed empty .zed directory');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Write back the modified config
|
|
||||||
fs.writeFileSync(
|
|
||||||
mcpConfigPath,
|
|
||||||
JSON.stringify(config, null, '\t') + '\n'
|
|
||||||
);
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[Zed] Removed TaskMaster from settings.json, preserved other configurations'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log('debug', '[Zed] TaskMaster not found in context_servers');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
log('error', `[Zed] Failed to clean up settings.json: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
|
||||||
// Handle .rules setup (same as onAddRulesProfile)
|
|
||||||
onAddRulesProfile(targetDir, assetsDir);
|
|
||||||
|
|
||||||
// Transform MCP config to Zed format
|
|
||||||
const mcpConfigPath = path.join(targetDir, '.zed', 'settings.json');
|
|
||||||
|
|
||||||
if (!fs.existsSync(mcpConfigPath)) {
|
|
||||||
log('debug', '[Zed] No .zed/settings.json found to transform');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Read the generated standard MCP config
|
|
||||||
const mcpConfigContent = fs.readFileSync(mcpConfigPath, 'utf8');
|
|
||||||
const mcpConfig = JSON.parse(mcpConfigContent);
|
|
||||||
|
|
||||||
// Check if it's already in Zed format (has context_servers)
|
|
||||||
if (mcpConfig['context_servers']) {
|
|
||||||
log(
|
|
||||||
'info',
|
|
||||||
'[Zed] settings.json already in Zed format, skipping transformation'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform to Zed format
|
|
||||||
const zedConfig = transformToZedFormat(mcpConfig);
|
|
||||||
|
|
||||||
// Write back the transformed config with proper formatting
|
|
||||||
fs.writeFileSync(
|
|
||||||
mcpConfigPath,
|
|
||||||
JSON.stringify(zedConfig, null, '\t') + '\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
log('info', '[Zed] Transformed settings.json to Zed format');
|
|
||||||
log('debug', '[Zed] Renamed mcpServers to context_servers');
|
|
||||||
} catch (error) {
|
|
||||||
log('error', `[Zed] Failed to transform settings.json: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and export zed profile using the base factory
|
|
||||||
export const zedProfile = createProfile({
|
|
||||||
name: 'zed',
|
|
||||||
displayName: 'Zed',
|
|
||||||
url: 'zed.dev',
|
|
||||||
docsUrl: 'zed.dev/docs',
|
|
||||||
profileDir: '.zed',
|
|
||||||
rulesDir: '.',
|
|
||||||
mcpConfig: true,
|
|
||||||
mcpConfigName: 'settings.json',
|
|
||||||
includeDefaultRules: false,
|
|
||||||
fileMap: {
|
|
||||||
'AGENTS.md': '.rules'
|
|
||||||
},
|
|
||||||
onAdd: onAddRulesProfile,
|
|
||||||
onRemove: onRemoveRulesProfile,
|
|
||||||
onPostConvert: onPostConvertRulesProfile
|
|
||||||
});
|
|
||||||
|
|
||||||
// Export lifecycle functions separately to avoid naming conflicts
|
|
||||||
export { onAddRulesProfile, onRemoveRulesProfile, onPostConvertRulesProfile };
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user