#
tokens: 48063/50000 16/975 files (page 19/69)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 19 of 69. Use http://codebase.md/eyaltoledano/claude-task-master?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .changeset
│   ├── config.json
│   └── README.md
├── .claude
│   ├── commands
│   │   └── dedupe.md
│   └── TM_COMMANDS_GUIDE.md
├── .claude-plugin
│   └── marketplace.json
├── .coderabbit.yaml
├── .cursor
│   ├── mcp.json
│   └── rules
│       ├── ai_providers.mdc
│       ├── ai_services.mdc
│       ├── architecture.mdc
│       ├── changeset.mdc
│       ├── commands.mdc
│       ├── context_gathering.mdc
│       ├── cursor_rules.mdc
│       ├── dependencies.mdc
│       ├── dev_workflow.mdc
│       ├── git_workflow.mdc
│       ├── glossary.mdc
│       ├── mcp.mdc
│       ├── new_features.mdc
│       ├── self_improve.mdc
│       ├── tags.mdc
│       ├── taskmaster.mdc
│       ├── tasks.mdc
│       ├── telemetry.mdc
│       ├── test_workflow.mdc
│       ├── tests.mdc
│       ├── ui.mdc
│       └── utilities.mdc
├── .cursorignore
├── .env.example
├── .github
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.md
│   │   ├── enhancements---feature-requests.md
│   │   └── feedback.md
│   ├── PULL_REQUEST_TEMPLATE
│   │   ├── bugfix.md
│   │   ├── config.yml
│   │   ├── feature.md
│   │   └── integration.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── scripts
│   │   ├── auto-close-duplicates.mjs
│   │   ├── backfill-duplicate-comments.mjs
│   │   ├── check-pre-release-mode.mjs
│   │   ├── parse-metrics.mjs
│   │   ├── release.mjs
│   │   ├── tag-extension.mjs
│   │   ├── utils.mjs
│   │   └── validate-changesets.mjs
│   └── workflows
│       ├── auto-close-duplicates.yml
│       ├── backfill-duplicate-comments.yml
│       ├── ci.yml
│       ├── claude-dedupe-issues.yml
│       ├── claude-docs-trigger.yml
│       ├── claude-docs-updater.yml
│       ├── claude-issue-triage.yml
│       ├── claude.yml
│       ├── extension-ci.yml
│       ├── extension-release.yml
│       ├── log-issue-events.yml
│       ├── pre-release.yml
│       ├── release-check.yml
│       ├── release.yml
│       ├── update-models-md.yml
│       └── weekly-metrics-discord.yml
├── .gitignore
├── .kiro
│   ├── hooks
│   │   ├── tm-code-change-task-tracker.kiro.hook
│   │   ├── tm-complexity-analyzer.kiro.hook
│   │   ├── tm-daily-standup-assistant.kiro.hook
│   │   ├── tm-git-commit-task-linker.kiro.hook
│   │   ├── tm-pr-readiness-checker.kiro.hook
│   │   ├── tm-task-dependency-auto-progression.kiro.hook
│   │   └── tm-test-success-task-completer.kiro.hook
│   ├── settings
│   │   └── mcp.json
│   └── steering
│       ├── dev_workflow.md
│       ├── kiro_rules.md
│       ├── self_improve.md
│       ├── taskmaster_hooks_workflow.md
│       └── taskmaster.md
├── .manypkg.json
├── .mcp.json
├── .npmignore
├── .nvmrc
├── .taskmaster
│   ├── CLAUDE.md
│   ├── config.json
│   ├── docs
│   │   ├── autonomous-tdd-git-workflow.md
│   │   ├── MIGRATION-ROADMAP.md
│   │   ├── prd-tm-start.txt
│   │   ├── prd.txt
│   │   ├── README.md
│   │   ├── research
│   │   │   ├── 2025-06-14_how-can-i-improve-the-scope-up-and-scope-down-comm.md
│   │   │   ├── 2025-06-14_should-i-be-using-any-specific-libraries-for-this.md
│   │   │   ├── 2025-06-14_test-save-functionality.md
│   │   │   ├── 2025-06-14_test-the-fix-for-duplicate-saves-final-test.md
│   │   │   └── 2025-08-01_do-we-need-to-add-new-commands-or-can-we-just-weap.md
│   │   ├── task-template-importing-prd.txt
│   │   ├── tdd-workflow-phase-0-spike.md
│   │   ├── tdd-workflow-phase-1-core-rails.md
│   │   ├── tdd-workflow-phase-1-orchestrator.md
│   │   ├── tdd-workflow-phase-2-pr-resumability.md
│   │   ├── tdd-workflow-phase-3-extensibility-guardrails.md
│   │   ├── test-prd.txt
│   │   └── tm-core-phase-1.txt
│   ├── reports
│   │   ├── task-complexity-report_autonomous-tdd-git-workflow.json
│   │   ├── task-complexity-report_cc-kiro-hooks.json
│   │   ├── task-complexity-report_tdd-phase-1-core-rails.json
│   │   ├── task-complexity-report_tdd-workflow-phase-0.json
│   │   ├── task-complexity-report_test-prd-tag.json
│   │   ├── task-complexity-report_tm-core-phase-1.json
│   │   ├── task-complexity-report.json
│   │   └── tm-core-complexity.json
│   ├── state.json
│   ├── tasks
│   │   ├── task_001_tm-start.txt
│   │   ├── task_002_tm-start.txt
│   │   ├── task_003_tm-start.txt
│   │   ├── task_004_tm-start.txt
│   │   ├── task_007_tm-start.txt
│   │   └── tasks.json
│   └── templates
│       ├── example_prd_rpg.md
│       └── example_prd.md
├── .vscode
│   ├── extensions.json
│   └── settings.json
├── apps
│   ├── cli
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── command-registry.ts
│   │   │   ├── commands
│   │   │   │   ├── auth.command.ts
│   │   │   │   ├── autopilot
│   │   │   │   │   ├── abort.command.ts
│   │   │   │   │   ├── commit.command.ts
│   │   │   │   │   ├── complete.command.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── next.command.ts
│   │   │   │   │   ├── resume.command.ts
│   │   │   │   │   ├── shared.ts
│   │   │   │   │   ├── start.command.ts
│   │   │   │   │   └── status.command.ts
│   │   │   │   ├── briefs.command.ts
│   │   │   │   ├── context.command.ts
│   │   │   │   ├── export.command.ts
│   │   │   │   ├── list.command.ts
│   │   │   │   ├── models
│   │   │   │   │   ├── custom-providers.ts
│   │   │   │   │   ├── fetchers.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── prompts.ts
│   │   │   │   │   ├── setup.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── next.command.ts
│   │   │   │   ├── set-status.command.ts
│   │   │   │   ├── show.command.ts
│   │   │   │   ├── start.command.ts
│   │   │   │   └── tags.command.ts
│   │   │   ├── index.ts
│   │   │   ├── lib
│   │   │   │   └── model-management.ts
│   │   │   ├── types
│   │   │   │   └── tag-management.d.ts
│   │   │   ├── ui
│   │   │   │   ├── components
│   │   │   │   │   ├── cardBox.component.ts
│   │   │   │   │   ├── dashboard.component.ts
│   │   │   │   │   ├── header.component.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── next-task.component.ts
│   │   │   │   │   ├── suggested-steps.component.ts
│   │   │   │   │   └── task-detail.component.ts
│   │   │   │   ├── display
│   │   │   │   │   ├── messages.ts
│   │   │   │   │   └── tables.ts
│   │   │   │   ├── formatters
│   │   │   │   │   ├── complexity-formatters.ts
│   │   │   │   │   ├── dependency-formatters.ts
│   │   │   │   │   ├── priority-formatters.ts
│   │   │   │   │   ├── status-formatters.spec.ts
│   │   │   │   │   └── status-formatters.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── layout
│   │   │   │       ├── helpers.spec.ts
│   │   │   │       └── helpers.ts
│   │   │   └── utils
│   │   │       ├── auth-helpers.ts
│   │   │       ├── auto-update.ts
│   │   │       ├── brief-selection.ts
│   │   │       ├── display-helpers.ts
│   │   │       ├── error-handler.ts
│   │   │       ├── index.ts
│   │   │       ├── project-root.ts
│   │   │       ├── task-status.ts
│   │   │       ├── ui.spec.ts
│   │   │       └── ui.ts
│   │   ├── tests
│   │   │   ├── integration
│   │   │   │   └── commands
│   │   │   │       └── autopilot
│   │   │   │           └── workflow.test.ts
│   │   │   └── unit
│   │   │       ├── commands
│   │   │       │   ├── autopilot
│   │   │       │   │   └── shared.test.ts
│   │   │       │   ├── list.command.spec.ts
│   │   │       │   └── show.command.spec.ts
│   │   │       └── ui
│   │   │           └── dashboard.component.spec.ts
│   │   ├── tsconfig.json
│   │   └── vitest.config.ts
│   ├── docs
│   │   ├── archive
│   │   │   ├── ai-client-utils-example.mdx
│   │   │   ├── ai-development-workflow.mdx
│   │   │   ├── command-reference.mdx
│   │   │   ├── configuration.mdx
│   │   │   ├── cursor-setup.mdx
│   │   │   ├── examples.mdx
│   │   │   └── Installation.mdx
│   │   ├── best-practices
│   │   │   ├── advanced-tasks.mdx
│   │   │   ├── configuration-advanced.mdx
│   │   │   └── index.mdx
│   │   ├── capabilities
│   │   │   ├── cli-root-commands.mdx
│   │   │   ├── index.mdx
│   │   │   ├── mcp.mdx
│   │   │   ├── rpg-method.mdx
│   │   │   └── task-structure.mdx
│   │   ├── CHANGELOG.md
│   │   ├── command-reference.mdx
│   │   ├── configuration.mdx
│   │   ├── docs.json
│   │   ├── favicon.svg
│   │   ├── getting-started
│   │   │   ├── api-keys.mdx
│   │   │   ├── contribute.mdx
│   │   │   ├── faq.mdx
│   │   │   └── quick-start
│   │   │       ├── configuration-quick.mdx
│   │   │       ├── execute-quick.mdx
│   │   │       ├── installation.mdx
│   │   │       ├── moving-forward.mdx
│   │   │       ├── prd-quick.mdx
│   │   │       ├── quick-start.mdx
│   │   │       ├── requirements.mdx
│   │   │       ├── rules-quick.mdx
│   │   │       └── tasks-quick.mdx
│   │   ├── introduction.mdx
│   │   ├── licensing.md
│   │   ├── logo
│   │   │   ├── dark.svg
│   │   │   ├── light.svg
│   │   │   └── task-master-logo.png
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── style.css
│   │   ├── tdd-workflow
│   │   │   ├── ai-agent-integration.mdx
│   │   │   └── quickstart.mdx
│   │   ├── vercel.json
│   │   └── whats-new.mdx
│   ├── extension
│   │   ├── .vscodeignore
│   │   ├── assets
│   │   │   ├── banner.png
│   │   │   ├── icon-dark.svg
│   │   │   ├── icon-light.svg
│   │   │   ├── icon.png
│   │   │   ├── screenshots
│   │   │   │   ├── kanban-board.png
│   │   │   │   └── task-details.png
│   │   │   └── sidebar-icon.svg
│   │   ├── CHANGELOG.md
│   │   ├── components.json
│   │   ├── docs
│   │   │   ├── extension-CI-setup.md
│   │   │   └── extension-development-guide.md
│   │   ├── esbuild.js
│   │   ├── LICENSE
│   │   ├── package.json
│   │   ├── package.mjs
│   │   ├── package.publish.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── components
│   │   │   │   ├── ConfigView.tsx
│   │   │   │   ├── constants.ts
│   │   │   │   ├── TaskDetails
│   │   │   │   │   ├── AIActionsSection.tsx
│   │   │   │   │   ├── DetailsSection.tsx
│   │   │   │   │   ├── PriorityBadge.tsx
│   │   │   │   │   ├── SubtasksSection.tsx
│   │   │   │   │   ├── TaskMetadataSidebar.tsx
│   │   │   │   │   └── useTaskDetails.ts
│   │   │   │   ├── TaskDetailsView.tsx
│   │   │   │   ├── TaskMasterLogo.tsx
│   │   │   │   └── ui
│   │   │   │       ├── badge.tsx
│   │   │   │       ├── breadcrumb.tsx
│   │   │   │       ├── button.tsx
│   │   │   │       ├── card.tsx
│   │   │   │       ├── collapsible.tsx
│   │   │   │       ├── CollapsibleSection.tsx
│   │   │   │       ├── dropdown-menu.tsx
│   │   │   │       ├── label.tsx
│   │   │   │       ├── scroll-area.tsx
│   │   │   │       ├── separator.tsx
│   │   │   │       ├── shadcn-io
│   │   │   │       │   └── kanban
│   │   │   │       │       └── index.tsx
│   │   │   │       └── textarea.tsx
│   │   │   ├── extension.ts
│   │   │   ├── index.ts
│   │   │   ├── lib
│   │   │   │   └── utils.ts
│   │   │   ├── services
│   │   │   │   ├── config-service.ts
│   │   │   │   ├── error-handler.ts
│   │   │   │   ├── notification-preferences.ts
│   │   │   │   ├── polling-service.ts
│   │   │   │   ├── polling-strategies.ts
│   │   │   │   ├── sidebar-webview-manager.ts
│   │   │   │   ├── task-repository.ts
│   │   │   │   ├── terminal-manager.ts
│   │   │   │   └── webview-manager.ts
│   │   │   ├── test
│   │   │   │   └── extension.test.ts
│   │   │   ├── utils
│   │   │   │   ├── configManager.ts
│   │   │   │   ├── connectionManager.ts
│   │   │   │   ├── errorHandler.ts
│   │   │   │   ├── event-emitter.ts
│   │   │   │   ├── logger.ts
│   │   │   │   ├── mcpClient.ts
│   │   │   │   ├── notificationPreferences.ts
│   │   │   │   └── task-master-api
│   │   │   │       ├── cache
│   │   │   │       │   └── cache-manager.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── mcp-client.ts
│   │   │   │       ├── transformers
│   │   │   │       │   └── task-transformer.ts
│   │   │   │       └── types
│   │   │   │           └── index.ts
│   │   │   └── webview
│   │   │       ├── App.tsx
│   │   │       ├── components
│   │   │       │   ├── AppContent.tsx
│   │   │       │   ├── EmptyState.tsx
│   │   │       │   ├── ErrorBoundary.tsx
│   │   │       │   ├── PollingStatus.tsx
│   │   │       │   ├── PriorityBadge.tsx
│   │   │       │   ├── SidebarView.tsx
│   │   │       │   ├── TagDropdown.tsx
│   │   │       │   ├── TaskCard.tsx
│   │   │       │   ├── TaskEditModal.tsx
│   │   │       │   ├── TaskMasterKanban.tsx
│   │   │       │   ├── ToastContainer.tsx
│   │   │       │   └── ToastNotification.tsx
│   │   │       ├── constants
│   │   │       │   └── index.ts
│   │   │       ├── contexts
│   │   │       │   └── VSCodeContext.tsx
│   │   │       ├── hooks
│   │   │       │   ├── useTaskQueries.ts
│   │   │       │   ├── useVSCodeMessages.ts
│   │   │       │   └── useWebviewHeight.ts
│   │   │       ├── index.css
│   │   │       ├── index.tsx
│   │   │       ├── providers
│   │   │       │   └── QueryProvider.tsx
│   │   │       ├── reducers
│   │   │       │   └── appReducer.ts
│   │   │       ├── sidebar.tsx
│   │   │       ├── types
│   │   │       │   └── index.ts
│   │   │       └── utils
│   │   │           ├── logger.ts
│   │   │           └── toast.ts
│   │   └── tsconfig.json
│   └── mcp
│       ├── CHANGELOG.md
│       ├── package.json
│       ├── src
│       │   ├── index.ts
│       │   ├── shared
│       │   │   ├── types.ts
│       │   │   └── utils.ts
│       │   └── tools
│       │       ├── autopilot
│       │       │   ├── abort.tool.ts
│       │       │   ├── commit.tool.ts
│       │       │   ├── complete.tool.ts
│       │       │   ├── finalize.tool.ts
│       │       │   ├── index.ts
│       │       │   ├── next.tool.ts
│       │       │   ├── resume.tool.ts
│       │       │   ├── start.tool.ts
│       │       │   └── status.tool.ts
│       │       ├── README-ZOD-V3.md
│       │       └── tasks
│       │           ├── get-task.tool.ts
│       │           ├── get-tasks.tool.ts
│       │           └── index.ts
│       ├── tsconfig.json
│       └── vitest.config.ts
├── assets
│   ├── .windsurfrules
│   ├── AGENTS.md
│   ├── claude
│   │   └── TM_COMMANDS_GUIDE.md
│   ├── config.json
│   ├── env.example
│   ├── example_prd_rpg.txt
│   ├── example_prd.txt
│   ├── GEMINI.md
│   ├── gitignore
│   ├── kiro-hooks
│   │   ├── tm-code-change-task-tracker.kiro.hook
│   │   ├── tm-complexity-analyzer.kiro.hook
│   │   ├── tm-daily-standup-assistant.kiro.hook
│   │   ├── tm-git-commit-task-linker.kiro.hook
│   │   ├── tm-pr-readiness-checker.kiro.hook
│   │   ├── tm-task-dependency-auto-progression.kiro.hook
│   │   └── tm-test-success-task-completer.kiro.hook
│   ├── roocode
│   │   ├── .roo
│   │   │   ├── rules-architect
│   │   │   │   └── architect-rules
│   │   │   ├── rules-ask
│   │   │   │   └── ask-rules
│   │   │   ├── rules-code
│   │   │   │   └── code-rules
│   │   │   ├── rules-debug
│   │   │   │   └── debug-rules
│   │   │   ├── rules-orchestrator
│   │   │   │   └── orchestrator-rules
│   │   │   └── rules-test
│   │   │       └── test-rules
│   │   └── .roomodes
│   ├── rules
│   │   ├── cursor_rules.mdc
│   │   ├── dev_workflow.mdc
│   │   ├── self_improve.mdc
│   │   ├── taskmaster_hooks_workflow.mdc
│   │   └── taskmaster.mdc
│   └── scripts_README.md
├── bin
│   └── task-master.js
├── biome.json
├── CHANGELOG.md
├── CLAUDE_CODE_PLUGIN.md
├── CLAUDE.md
├── context
│   ├── chats
│   │   ├── add-task-dependencies-1.md
│   │   └── max-min-tokens.txt.md
│   ├── fastmcp-core.txt
│   ├── fastmcp-docs.txt
│   ├── MCP_INTEGRATION.md
│   ├── mcp-js-sdk-docs.txt
│   ├── mcp-protocol-repo.txt
│   ├── mcp-protocol-schema-03262025.json
│   └── mcp-protocol-spec.txt
├── CONTRIBUTING.md
├── docs
│   ├── claude-code-integration.md
│   ├── CLI-COMMANDER-PATTERN.md
│   ├── command-reference.md
│   ├── configuration.md
│   ├── contributor-docs
│   │   ├── testing-roo-integration.md
│   │   └── worktree-setup.md
│   ├── cross-tag-task-movement.md
│   ├── examples
│   │   ├── claude-code-usage.md
│   │   └── codex-cli-usage.md
│   ├── examples.md
│   ├── licensing.md
│   ├── mcp-provider-guide.md
│   ├── mcp-provider.md
│   ├── migration-guide.md
│   ├── models.md
│   ├── providers
│   │   ├── codex-cli.md
│   │   └── gemini-cli.md
│   ├── README.md
│   ├── scripts
│   │   └── models-json-to-markdown.js
│   ├── task-structure.md
│   └── tutorial.md
├── images
│   ├── hamster-hiring.png
│   └── logo.png
├── index.js
├── jest.config.js
├── jest.resolver.cjs
├── LICENSE
├── llms-install.md
├── mcp-server
│   ├── server.js
│   └── src
│       ├── core
│       │   ├── __tests__
│       │   │   └── context-manager.test.js
│       │   ├── context-manager.js
│       │   ├── direct-functions
│       │   │   ├── add-dependency.js
│       │   │   ├── add-subtask.js
│       │   │   ├── add-tag.js
│       │   │   ├── add-task.js
│       │   │   ├── analyze-task-complexity.js
│       │   │   ├── cache-stats.js
│       │   │   ├── clear-subtasks.js
│       │   │   ├── complexity-report.js
│       │   │   ├── copy-tag.js
│       │   │   ├── create-tag-from-branch.js
│       │   │   ├── delete-tag.js
│       │   │   ├── expand-all-tasks.js
│       │   │   ├── expand-task.js
│       │   │   ├── fix-dependencies.js
│       │   │   ├── generate-task-files.js
│       │   │   ├── initialize-project.js
│       │   │   ├── list-tags.js
│       │   │   ├── models.js
│       │   │   ├── move-task-cross-tag.js
│       │   │   ├── move-task.js
│       │   │   ├── next-task.js
│       │   │   ├── parse-prd.js
│       │   │   ├── remove-dependency.js
│       │   │   ├── remove-subtask.js
│       │   │   ├── remove-task.js
│       │   │   ├── rename-tag.js
│       │   │   ├── research.js
│       │   │   ├── response-language.js
│       │   │   ├── rules.js
│       │   │   ├── scope-down.js
│       │   │   ├── scope-up.js
│       │   │   ├── set-task-status.js
│       │   │   ├── update-subtask-by-id.js
│       │   │   ├── update-task-by-id.js
│       │   │   ├── update-tasks.js
│       │   │   ├── use-tag.js
│       │   │   └── validate-dependencies.js
│       │   ├── task-master-core.js
│       │   └── utils
│       │       ├── env-utils.js
│       │       └── path-utils.js
│       ├── custom-sdk
│       │   ├── errors.js
│       │   ├── index.js
│       │   ├── json-extractor.js
│       │   ├── language-model.js
│       │   ├── message-converter.js
│       │   └── schema-converter.js
│       ├── index.js
│       ├── logger.js
│       ├── providers
│       │   └── mcp-provider.js
│       └── tools
│           ├── add-dependency.js
│           ├── add-subtask.js
│           ├── add-tag.js
│           ├── add-task.js
│           ├── analyze.js
│           ├── clear-subtasks.js
│           ├── complexity-report.js
│           ├── copy-tag.js
│           ├── delete-tag.js
│           ├── expand-all.js
│           ├── expand-task.js
│           ├── fix-dependencies.js
│           ├── generate.js
│           ├── get-operation-status.js
│           ├── index.js
│           ├── initialize-project.js
│           ├── list-tags.js
│           ├── models.js
│           ├── move-task.js
│           ├── next-task.js
│           ├── parse-prd.js
│           ├── README-ZOD-V3.md
│           ├── remove-dependency.js
│           ├── remove-subtask.js
│           ├── remove-task.js
│           ├── rename-tag.js
│           ├── research.js
│           ├── response-language.js
│           ├── rules.js
│           ├── scope-down.js
│           ├── scope-up.js
│           ├── set-task-status.js
│           ├── tool-registry.js
│           ├── update-subtask.js
│           ├── update-task.js
│           ├── update.js
│           ├── use-tag.js
│           ├── utils.js
│           └── validate-dependencies.js
├── mcp-test.js
├── output.json
├── package-lock.json
├── package.json
├── packages
│   ├── ai-sdk-provider-grok-cli
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── errors.test.ts
│   │   │   ├── errors.ts
│   │   │   ├── grok-cli-language-model.ts
│   │   │   ├── grok-cli-provider.test.ts
│   │   │   ├── grok-cli-provider.ts
│   │   │   ├── index.ts
│   │   │   ├── json-extractor.test.ts
│   │   │   ├── json-extractor.ts
│   │   │   ├── message-converter.test.ts
│   │   │   ├── message-converter.ts
│   │   │   └── types.ts
│   │   └── tsconfig.json
│   ├── build-config
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── src
│   │   │   └── tsdown.base.ts
│   │   └── tsconfig.json
│   ├── claude-code-plugin
│   │   ├── .claude-plugin
│   │   │   └── plugin.json
│   │   ├── .gitignore
│   │   ├── agents
│   │   │   ├── task-checker.md
│   │   │   ├── task-executor.md
│   │   │   └── task-orchestrator.md
│   │   ├── CHANGELOG.md
│   │   ├── commands
│   │   │   ├── add-dependency.md
│   │   │   ├── add-subtask.md
│   │   │   ├── add-task.md
│   │   │   ├── analyze-complexity.md
│   │   │   ├── analyze-project.md
│   │   │   ├── auto-implement-tasks.md
│   │   │   ├── command-pipeline.md
│   │   │   ├── complexity-report.md
│   │   │   ├── convert-task-to-subtask.md
│   │   │   ├── expand-all-tasks.md
│   │   │   ├── expand-task.md
│   │   │   ├── fix-dependencies.md
│   │   │   ├── generate-tasks.md
│   │   │   ├── help.md
│   │   │   ├── init-project-quick.md
│   │   │   ├── init-project.md
│   │   │   ├── install-taskmaster.md
│   │   │   ├── learn.md
│   │   │   ├── list-tasks-by-status.md
│   │   │   ├── list-tasks-with-subtasks.md
│   │   │   ├── list-tasks.md
│   │   │   ├── next-task.md
│   │   │   ├── parse-prd-with-research.md
│   │   │   ├── parse-prd.md
│   │   │   ├── project-status.md
│   │   │   ├── quick-install-taskmaster.md
│   │   │   ├── remove-all-subtasks.md
│   │   │   ├── remove-dependency.md
│   │   │   ├── remove-subtask.md
│   │   │   ├── remove-subtasks.md
│   │   │   ├── remove-task.md
│   │   │   ├── setup-models.md
│   │   │   ├── show-task.md
│   │   │   ├── smart-workflow.md
│   │   │   ├── sync-readme.md
│   │   │   ├── tm-main.md
│   │   │   ├── to-cancelled.md
│   │   │   ├── to-deferred.md
│   │   │   ├── to-done.md
│   │   │   ├── to-in-progress.md
│   │   │   ├── to-pending.md
│   │   │   ├── to-review.md
│   │   │   ├── update-single-task.md
│   │   │   ├── update-task.md
│   │   │   ├── update-tasks-from-id.md
│   │   │   ├── validate-dependencies.md
│   │   │   └── view-models.md
│   │   ├── mcp.json
│   │   └── package.json
│   ├── tm-bridge
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── add-tag-bridge.ts
│   │   │   ├── bridge-types.ts
│   │   │   ├── bridge-utils.ts
│   │   │   ├── expand-bridge.ts
│   │   │   ├── index.ts
│   │   │   ├── tags-bridge.ts
│   │   │   ├── update-bridge.ts
│   │   │   └── use-tag-bridge.ts
│   │   └── tsconfig.json
│   └── tm-core
│       ├── .gitignore
│       ├── CHANGELOG.md
│       ├── docs
│       │   └── listTasks-architecture.md
│       ├── package.json
│       ├── POC-STATUS.md
│       ├── README.md
│       ├── src
│       │   ├── common
│       │   │   ├── constants
│       │   │   │   ├── index.ts
│       │   │   │   ├── paths.ts
│       │   │   │   └── providers.ts
│       │   │   ├── errors
│       │   │   │   ├── index.ts
│       │   │   │   └── task-master-error.ts
│       │   │   ├── interfaces
│       │   │   │   ├── configuration.interface.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── storage.interface.ts
│       │   │   ├── logger
│       │   │   │   ├── factory.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── logger.spec.ts
│       │   │   │   └── logger.ts
│       │   │   ├── mappers
│       │   │   │   ├── TaskMapper.test.ts
│       │   │   │   └── TaskMapper.ts
│       │   │   ├── types
│       │   │   │   ├── database.types.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── legacy.ts
│       │   │   │   └── repository-types.ts
│       │   │   └── utils
│       │   │       ├── git-utils.ts
│       │   │       ├── id-generator.ts
│       │   │       ├── index.ts
│       │   │       ├── path-helpers.ts
│       │   │       ├── path-normalizer.spec.ts
│       │   │       ├── path-normalizer.ts
│       │   │       ├── project-root-finder.spec.ts
│       │   │       ├── project-root-finder.ts
│       │   │       ├── run-id-generator.spec.ts
│       │   │       └── run-id-generator.ts
│       │   ├── index.ts
│       │   ├── modules
│       │   │   ├── ai
│       │   │   │   ├── index.ts
│       │   │   │   ├── interfaces
│       │   │   │   │   └── ai-provider.interface.ts
│       │   │   │   └── providers
│       │   │   │       ├── base-provider.ts
│       │   │   │       └── index.ts
│       │   │   ├── auth
│       │   │   │   ├── auth-domain.spec.ts
│       │   │   │   ├── auth-domain.ts
│       │   │   │   ├── config.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── managers
│       │   │   │   │   ├── auth-manager.spec.ts
│       │   │   │   │   └── auth-manager.ts
│       │   │   │   ├── services
│       │   │   │   │   ├── context-store.ts
│       │   │   │   │   ├── oauth-service.ts
│       │   │   │   │   ├── organization.service.ts
│       │   │   │   │   ├── supabase-session-storage.spec.ts
│       │   │   │   │   └── supabase-session-storage.ts
│       │   │   │   └── types.ts
│       │   │   ├── briefs
│       │   │   │   ├── briefs-domain.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── services
│       │   │   │   │   └── brief-service.ts
│       │   │   │   ├── types.ts
│       │   │   │   └── utils
│       │   │   │       └── url-parser.ts
│       │   │   ├── commands
│       │   │   │   └── index.ts
│       │   │   ├── config
│       │   │   │   ├── config-domain.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── managers
│       │   │   │   │   ├── config-manager.spec.ts
│       │   │   │   │   └── config-manager.ts
│       │   │   │   └── services
│       │   │   │       ├── config-loader.service.spec.ts
│       │   │   │       ├── config-loader.service.ts
│       │   │   │       ├── config-merger.service.spec.ts
│       │   │   │       ├── config-merger.service.ts
│       │   │   │       ├── config-persistence.service.spec.ts
│       │   │   │       ├── config-persistence.service.ts
│       │   │   │       ├── environment-config-provider.service.spec.ts
│       │   │   │       ├── environment-config-provider.service.ts
│       │   │   │       ├── index.ts
│       │   │   │       ├── runtime-state-manager.service.spec.ts
│       │   │   │       └── runtime-state-manager.service.ts
│       │   │   ├── dependencies
│       │   │   │   └── index.ts
│       │   │   ├── execution
│       │   │   │   ├── executors
│       │   │   │   │   ├── base-executor.ts
│       │   │   │   │   ├── claude-executor.ts
│       │   │   │   │   └── executor-factory.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── services
│       │   │   │   │   └── executor-service.ts
│       │   │   │   └── types.ts
│       │   │   ├── git
│       │   │   │   ├── adapters
│       │   │   │   │   ├── git-adapter.test.ts
│       │   │   │   │   └── git-adapter.ts
│       │   │   │   ├── git-domain.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── services
│       │   │   │       ├── branch-name-generator.spec.ts
│       │   │   │       ├── branch-name-generator.ts
│       │   │   │       ├── commit-message-generator.test.ts
│       │   │   │       ├── commit-message-generator.ts
│       │   │   │       ├── scope-detector.test.ts
│       │   │   │       ├── scope-detector.ts
│       │   │   │       ├── template-engine.test.ts
│       │   │   │       └── template-engine.ts
│       │   │   ├── integration
│       │   │   │   ├── clients
│       │   │   │   │   ├── index.ts
│       │   │   │   │   └── supabase-client.ts
│       │   │   │   ├── integration-domain.ts
│       │   │   │   └── services
│       │   │   │       ├── export.service.ts
│       │   │   │       ├── task-expansion.service.ts
│       │   │   │       └── task-retrieval.service.ts
│       │   │   ├── reports
│       │   │   │   ├── index.ts
│       │   │   │   ├── managers
│       │   │   │   │   └── complexity-report-manager.ts
│       │   │   │   └── types.ts
│       │   │   ├── storage
│       │   │   │   ├── adapters
│       │   │   │   │   ├── activity-logger.ts
│       │   │   │   │   ├── api-storage.ts
│       │   │   │   │   └── file-storage
│       │   │   │   │       ├── file-operations.ts
│       │   │   │   │       ├── file-storage.ts
│       │   │   │   │       ├── format-handler.ts
│       │   │   │   │       ├── index.ts
│       │   │   │   │       └── path-resolver.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── services
│       │   │   │   │   └── storage-factory.ts
│       │   │   │   └── utils
│       │   │   │       └── api-client.ts
│       │   │   ├── tasks
│       │   │   │   ├── entities
│       │   │   │   │   └── task.entity.ts
│       │   │   │   ├── parser
│       │   │   │   │   └── index.ts
│       │   │   │   ├── repositories
│       │   │   │   │   ├── supabase
│       │   │   │   │   │   ├── dependency-fetcher.ts
│       │   │   │   │   │   ├── index.ts
│       │   │   │   │   │   └── supabase-repository.ts
│       │   │   │   │   └── task-repository.interface.ts
│       │   │   │   ├── services
│       │   │   │   │   ├── preflight-checker.service.ts
│       │   │   │   │   ├── tag.service.ts
│       │   │   │   │   ├── task-execution-service.ts
│       │   │   │   │   ├── task-loader.service.ts
│       │   │   │   │   └── task-service.ts
│       │   │   │   └── tasks-domain.ts
│       │   │   ├── ui
│       │   │   │   └── index.ts
│       │   │   └── workflow
│       │   │       ├── managers
│       │   │       │   ├── workflow-state-manager.spec.ts
│       │   │       │   └── workflow-state-manager.ts
│       │   │       ├── orchestrators
│       │   │       │   ├── workflow-orchestrator.test.ts
│       │   │       │   └── workflow-orchestrator.ts
│       │   │       ├── services
│       │   │       │   ├── test-result-validator.test.ts
│       │   │       │   ├── test-result-validator.ts
│       │   │       │   ├── test-result-validator.types.ts
│       │   │       │   ├── workflow-activity-logger.ts
│       │   │       │   └── workflow.service.ts
│       │   │       ├── types.ts
│       │   │       └── workflow-domain.ts
│       │   ├── subpath-exports.test.ts
│       │   ├── tm-core.ts
│       │   └── utils
│       │       └── time.utils.ts
│       ├── tests
│       │   ├── auth
│       │   │   └── auth-refresh.test.ts
│       │   ├── integration
│       │   │   ├── auth-token-refresh.test.ts
│       │   │   ├── list-tasks.test.ts
│       │   │   └── storage
│       │   │       └── activity-logger.test.ts
│       │   ├── mocks
│       │   │   └── mock-provider.ts
│       │   ├── setup.ts
│       │   └── unit
│       │       ├── base-provider.test.ts
│       │       ├── executor.test.ts
│       │       └── smoke.test.ts
│       ├── tsconfig.json
│       └── vitest.config.ts
├── README-task-master.md
├── README.md
├── scripts
│   ├── create-worktree.sh
│   ├── dev.js
│   ├── init.js
│   ├── list-worktrees.sh
│   ├── modules
│   │   ├── ai-services-unified.js
│   │   ├── bridge-utils.js
│   │   ├── commands.js
│   │   ├── config-manager.js
│   │   ├── dependency-manager.js
│   │   ├── index.js
│   │   ├── prompt-manager.js
│   │   ├── supported-models.json
│   │   ├── sync-readme.js
│   │   ├── task-manager
│   │   │   ├── add-subtask.js
│   │   │   ├── add-task.js
│   │   │   ├── analyze-task-complexity.js
│   │   │   ├── clear-subtasks.js
│   │   │   ├── expand-all-tasks.js
│   │   │   ├── expand-task.js
│   │   │   ├── find-next-task.js
│   │   │   ├── generate-task-files.js
│   │   │   ├── is-task-dependent.js
│   │   │   ├── list-tasks.js
│   │   │   ├── migrate.js
│   │   │   ├── models.js
│   │   │   ├── move-task.js
│   │   │   ├── parse-prd
│   │   │   │   ├── index.js
│   │   │   │   ├── parse-prd-config.js
│   │   │   │   ├── parse-prd-helpers.js
│   │   │   │   ├── parse-prd-non-streaming.js
│   │   │   │   ├── parse-prd-streaming.js
│   │   │   │   └── parse-prd.js
│   │   │   ├── remove-subtask.js
│   │   │   ├── remove-task.js
│   │   │   ├── research.js
│   │   │   ├── response-language.js
│   │   │   ├── scope-adjustment.js
│   │   │   ├── set-task-status.js
│   │   │   ├── tag-management.js
│   │   │   ├── task-exists.js
│   │   │   ├── update-single-task-status.js
│   │   │   ├── update-subtask-by-id.js
│   │   │   ├── update-task-by-id.js
│   │   │   └── update-tasks.js
│   │   ├── task-manager.js
│   │   ├── ui.js
│   │   ├── update-config-tokens.js
│   │   ├── utils
│   │   │   ├── contextGatherer.js
│   │   │   ├── fuzzyTaskSearch.js
│   │   │   └── git-utils.js
│   │   └── utils.js
│   ├── task-complexity-report.json
│   ├── test-claude-errors.js
│   └── test-claude.js
├── sonar-project.properties
├── src
│   ├── ai-providers
│   │   ├── anthropic.js
│   │   ├── azure.js
│   │   ├── base-provider.js
│   │   ├── bedrock.js
│   │   ├── claude-code.js
│   │   ├── codex-cli.js
│   │   ├── gemini-cli.js
│   │   ├── google-vertex.js
│   │   ├── google.js
│   │   ├── grok-cli.js
│   │   ├── groq.js
│   │   ├── index.js
│   │   ├── lmstudio.js
│   │   ├── ollama.js
│   │   ├── openai-compatible.js
│   │   ├── openai.js
│   │   ├── openrouter.js
│   │   ├── perplexity.js
│   │   ├── xai.js
│   │   ├── zai-coding.js
│   │   └── zai.js
│   ├── constants
│   │   ├── commands.js
│   │   ├── paths.js
│   │   ├── profiles.js
│   │   ├── rules-actions.js
│   │   ├── task-priority.js
│   │   └── task-status.js
│   ├── profiles
│   │   ├── amp.js
│   │   ├── base-profile.js
│   │   ├── claude.js
│   │   ├── cline.js
│   │   ├── codex.js
│   │   ├── cursor.js
│   │   ├── gemini.js
│   │   ├── index.js
│   │   ├── kilo.js
│   │   ├── kiro.js
│   │   ├── opencode.js
│   │   ├── roo.js
│   │   ├── trae.js
│   │   ├── vscode.js
│   │   ├── windsurf.js
│   │   └── zed.js
│   ├── progress
│   │   ├── base-progress-tracker.js
│   │   ├── cli-progress-factory.js
│   │   ├── parse-prd-tracker.js
│   │   ├── progress-tracker-builder.js
│   │   └── tracker-ui.js
│   ├── prompts
│   │   ├── add-task.json
│   │   ├── analyze-complexity.json
│   │   ├── expand-task.json
│   │   ├── parse-prd.json
│   │   ├── README.md
│   │   ├── research.json
│   │   ├── schemas
│   │   │   ├── parameter.schema.json
│   │   │   ├── prompt-template.schema.json
│   │   │   ├── README.md
│   │   │   └── variant.schema.json
│   │   ├── update-subtask.json
│   │   ├── update-task.json
│   │   └── update-tasks.json
│   ├── provider-registry
│   │   └── index.js
│   ├── schemas
│   │   ├── add-task.js
│   │   ├── analyze-complexity.js
│   │   ├── base-schemas.js
│   │   ├── expand-task.js
│   │   ├── parse-prd.js
│   │   ├── registry.js
│   │   ├── update-subtask.js
│   │   ├── update-task.js
│   │   └── update-tasks.js
│   ├── task-master.js
│   ├── ui
│   │   ├── confirm.js
│   │   ├── indicators.js
│   │   └── parse-prd.js
│   └── utils
│       ├── asset-resolver.js
│       ├── create-mcp-config.js
│       ├── format.js
│       ├── getVersion.js
│       ├── logger-utils.js
│       ├── manage-gitignore.js
│       ├── path-utils.js
│       ├── profiles.js
│       ├── rule-transformer.js
│       ├── stream-parser.js
│       └── timeout-manager.js
├── test-clean-tags.js
├── test-config-manager.js
├── test-prd.txt
├── test-tag-functions.js
├── test-version-check-full.js
├── test-version-check.js
├── tests
│   ├── e2e
│   │   ├── e2e_helpers.sh
│   │   ├── parse_llm_output.cjs
│   │   ├── run_e2e.sh
│   │   ├── run_fallback_verification.sh
│   │   └── test_llm_analysis.sh
│   ├── fixtures
│   │   ├── .taskmasterconfig
│   │   ├── sample-claude-response.js
│   │   ├── sample-prd.txt
│   │   └── sample-tasks.js
│   ├── helpers
│   │   └── tool-counts.js
│   ├── integration
│   │   ├── claude-code-error-handling.test.js
│   │   ├── claude-code-optional.test.js
│   │   ├── cli
│   │   │   ├── commands.test.js
│   │   │   ├── complex-cross-tag-scenarios.test.js
│   │   │   └── move-cross-tag.test.js
│   │   ├── manage-gitignore.test.js
│   │   ├── mcp-server
│   │   │   └── direct-functions.test.js
│   │   ├── move-task-cross-tag.integration.test.js
│   │   ├── move-task-simple.integration.test.js
│   │   ├── profiles
│   │   │   ├── amp-init-functionality.test.js
│   │   │   ├── claude-init-functionality.test.js
│   │   │   ├── cline-init-functionality.test.js
│   │   │   ├── codex-init-functionality.test.js
│   │   │   ├── cursor-init-functionality.test.js
│   │   │   ├── gemini-init-functionality.test.js
│   │   │   ├── opencode-init-functionality.test.js
│   │   │   ├── roo-files-inclusion.test.js
│   │   │   ├── roo-init-functionality.test.js
│   │   │   ├── rules-files-inclusion.test.js
│   │   │   ├── trae-init-functionality.test.js
│   │   │   ├── vscode-init-functionality.test.js
│   │   │   └── windsurf-init-functionality.test.js
│   │   └── providers
│   │       └── temperature-support.test.js
│   ├── manual
│   │   ├── progress
│   │   │   ├── parse-prd-analysis.js
│   │   │   ├── test-parse-prd.js
│   │   │   └── TESTING_GUIDE.md
│   │   └── prompts
│   │       ├── prompt-test.js
│   │       └── README.md
│   ├── README.md
│   ├── setup.js
│   └── unit
│       ├── ai-providers
│       │   ├── base-provider.test.js
│       │   ├── claude-code.test.js
│       │   ├── codex-cli.test.js
│       │   ├── gemini-cli.test.js
│       │   ├── lmstudio.test.js
│       │   ├── mcp-components.test.js
│       │   ├── openai-compatible.test.js
│       │   ├── openai.test.js
│       │   ├── provider-registry.test.js
│       │   ├── zai-coding.test.js
│       │   ├── zai-provider.test.js
│       │   ├── zai-schema-introspection.test.js
│       │   └── zai.test.js
│       ├── ai-services-unified.test.js
│       ├── commands.test.js
│       ├── config-manager.test.js
│       ├── config-manager.test.mjs
│       ├── dependency-manager.test.js
│       ├── init.test.js
│       ├── initialize-project.test.js
│       ├── kebab-case-validation.test.js
│       ├── manage-gitignore.test.js
│       ├── mcp
│       │   └── tools
│       │       ├── __mocks__
│       │       │   └── move-task.js
│       │       ├── add-task.test.js
│       │       ├── analyze-complexity.test.js
│       │       ├── expand-all.test.js
│       │       ├── get-tasks.test.js
│       │       ├── initialize-project.test.js
│       │       ├── move-task-cross-tag-options.test.js
│       │       ├── move-task-cross-tag.test.js
│       │       ├── remove-task.test.js
│       │       └── tool-registration.test.js
│       ├── mcp-providers
│       │   ├── mcp-components.test.js
│       │   └── mcp-provider.test.js
│       ├── parse-prd.test.js
│       ├── profiles
│       │   ├── amp-integration.test.js
│       │   ├── claude-integration.test.js
│       │   ├── cline-integration.test.js
│       │   ├── codex-integration.test.js
│       │   ├── cursor-integration.test.js
│       │   ├── gemini-integration.test.js
│       │   ├── kilo-integration.test.js
│       │   ├── kiro-integration.test.js
│       │   ├── mcp-config-validation.test.js
│       │   ├── opencode-integration.test.js
│       │   ├── profile-safety-check.test.js
│       │   ├── roo-integration.test.js
│       │   ├── rule-transformer-cline.test.js
│       │   ├── rule-transformer-cursor.test.js
│       │   ├── rule-transformer-gemini.test.js
│       │   ├── rule-transformer-kilo.test.js
│       │   ├── rule-transformer-kiro.test.js
│       │   ├── rule-transformer-opencode.test.js
│       │   ├── rule-transformer-roo.test.js
│       │   ├── rule-transformer-trae.test.js
│       │   ├── rule-transformer-vscode.test.js
│       │   ├── rule-transformer-windsurf.test.js
│       │   ├── rule-transformer-zed.test.js
│       │   ├── rule-transformer.test.js
│       │   ├── selective-profile-removal.test.js
│       │   ├── subdirectory-support.test.js
│       │   ├── trae-integration.test.js
│       │   ├── vscode-integration.test.js
│       │   ├── windsurf-integration.test.js
│       │   └── zed-integration.test.js
│       ├── progress
│       │   └── base-progress-tracker.test.js
│       ├── prompt-manager.test.js
│       ├── prompts
│       │   ├── expand-task-prompt.test.js
│       │   └── prompt-migration.test.js
│       ├── scripts
│       │   └── modules
│       │       ├── commands
│       │       │   ├── move-cross-tag.test.js
│       │       │   └── README.md
│       │       ├── dependency-manager
│       │       │   ├── circular-dependencies.test.js
│       │       │   ├── cross-tag-dependencies.test.js
│       │       │   └── fix-dependencies-command.test.js
│       │       ├── task-manager
│       │       │   ├── add-subtask.test.js
│       │       │   ├── add-task.test.js
│       │       │   ├── analyze-task-complexity.test.js
│       │       │   ├── clear-subtasks.test.js
│       │       │   ├── complexity-report-tag-isolation.test.js
│       │       │   ├── expand-all-tasks.test.js
│       │       │   ├── expand-task.test.js
│       │       │   ├── find-next-task.test.js
│       │       │   ├── generate-task-files.test.js
│       │       │   ├── list-tasks.test.js
│       │       │   ├── models-baseurl.test.js
│       │       │   ├── move-task-cross-tag.test.js
│       │       │   ├── move-task.test.js
│       │       │   ├── parse-prd-schema.test.js
│       │       │   ├── parse-prd.test.js
│       │       │   ├── remove-subtask.test.js
│       │       │   ├── remove-task.test.js
│       │       │   ├── research.test.js
│       │       │   ├── scope-adjustment.test.js
│       │       │   ├── set-task-status.test.js
│       │       │   ├── setup.js
│       │       │   ├── update-single-task-status.test.js
│       │       │   ├── update-subtask-by-id.test.js
│       │       │   ├── update-task-by-id.test.js
│       │       │   └── update-tasks.test.js
│       │       ├── ui
│       │       │   └── cross-tag-error-display.test.js
│       │       └── utils-tag-aware-paths.test.js
│       ├── task-finder.test.js
│       ├── task-manager
│       │   ├── clear-subtasks.test.js
│       │   ├── move-task.test.js
│       │   ├── tag-boundary.test.js
│       │   └── tag-management.test.js
│       ├── task-master.test.js
│       ├── ui
│       │   └── indicators.test.js
│       ├── ui.test.js
│       ├── utils-strip-ansi.test.js
│       └── utils.test.js
├── tsconfig.json
├── tsdown.config.ts
├── turbo.json
└── update-task-migration-plan.md
```

# Files

--------------------------------------------------------------------------------
/.taskmaster/docs/research/2025-06-14_should-i-be-using-any-specific-libraries-for-this.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: Research Session
  3 | query: "should i be using any specific libraries for this?"
  4 | date: 6/14/2025
  5 | time: 5:20:00 PM
  6 | timestamp: 2025-06-14T21:20:00.561Z
  7 | exchanges: 2
  8 | ---
  9 | 
 10 | # Research Session
 11 | 
 12 | ## Initial Query
 13 | 
 14 | **Question:** should i be using any specific libraries for this?
 15 | 
 16 | **Response:**
 17 | 
 18 | HELL YEAH PARTNER
 19 | 
 20 | For implementing a GitHub Issue export feature with bidirectional linking in your project, you absolutely should use a dedicated library for interacting with the GitHub API. This will save you a ton of time, reduce boilerplate, and help you avoid common pitfalls with authentication, pagination, and error handling.
 21 | 
 22 | ## Recommended Library: PyGithub
 23 | 
 24 | - **PyGithub** is the most widely used and well-documented Python library for accessing the GitHub REST API v3. It allows you to manage repositories, issues, user profiles, and more, all with a clean, object-oriented interface[1][2][3][5].
 25 | - It supports all the operations you’ll need for your export feature, including creating issues, updating them, and managing references for bidirectional linking.
 26 | 
 27 | ### Key Features
 28 | 
 29 | - **Authentication**: Easily authenticate with a personal access token.
 30 | - **Issue Management**: Create, update, and link issues programmatically.
 31 | - **Repository Access**: Fetch and manipulate repository data.
 32 | - **User/Org Support**: Works for both user and organization repos.
 33 | - **Pagination & Rate Limiting**: Handles these for you.
 34 | 
 35 | ### Example Usage
 36 | 
 37 | ```python
 38 | from github import Github, Auth
 39 | 
 40 | # Authenticate with a personal access token
 41 | auth = Auth.Token("your_github_token")
 42 | g = Github(auth=auth)
 43 | 
 44 | # Get the repo
 45 | repo = g.get_repo("owner/repo_name")
 46 | 
 47 | # Create a new issue
 48 | issue = repo.create_issue(
 49 |     title="Exported from Task Master",
 50 |     body="This issue was created by Task Master. [Task ID: 123]"
 51 | )
 52 | 
 53 | # Add a comment or update the issue to include a backlink
 54 | issue.create_comment("Linked to Task Master task #123")
 55 | ```
 56 | [3][5]
 57 | 
 58 | ## Why Not Use Raw Requests?
 59 | 
 60 | - While you *can* use the `requests` library to call the GitHub API directly[4], PyGithub abstracts away authentication, error handling, and pagination, making your code much cleaner and less error-prone[2][5].
 61 | 
 62 | ## Integration Tips
 63 | 
 64 | - Store your GitHub token securely (e.g., in environment variables).
 65 | - Use PyGithub’s objects to fetch, create, and update issues.
 66 | - For bidirectional linking, store the GitHub issue URL in your task data and the Task Master task ID in the GitHub issue body or as a label/comment.
 67 | - PyGithub is actively maintained and widely used, so you’ll find plenty of support and documentation.
 68 | 
 69 | ## Installation
 70 | 
 71 | ```bash
 72 | pip install PyGithub
 73 | ```
 74 | [3]
 75 | 
 76 | ## Summary Table
 77 | 
 78 | | Library   | Language | API Coverage | Ease of Use | Maintained | Docs/Support |
 79 | |-----------|----------|--------------|-------------|------------|--------------|
 80 | | PyGithub  | Python   | Full         | High        | Yes        | Excellent    |
 81 | | requests  | Python   | Full (manual)| Medium      | Yes        | Good         |
 82 | 
 83 | **Use PyGithub for all GitHub API interactions in your export/import features.** It’s the standard for Python projects and will make your implementation faster, safer, and more maintainable[1][2][3][5].
 84 | 
 85 | ---
 86 | 
 87 | ## Follow-up 1
 88 | 
 89 | **Question:** we don't want to use py github because we have a node project
 90 | 
 91 | **Response:**
 92 | 
 93 | HELL YEAH PARTNER
 94 | 
 95 | For a Node.js project, you should use a Node-native library to interact with the GitHub API instead of PyGithub, which is Python-only. The industry standard for Node.js is **Octokit**, the official GitHub SDK for JavaScript/TypeScript[1][2].
 96 | 
 97 | ## Why Use Octokit?
 98 | 
 99 | - **Official & Complete**: Octokit is maintained by GitHub and covers all REST and GraphQL API endpoints, including issues, repositories, users, and more[1][2].
100 | - **Universal**: Works in Node.js, browsers, and Deno environments[2].
101 | - **Typed & Tested**: Comes with TypeScript declarations and 100% test coverage[2].
102 | - **Authentication**: Supports personal access tokens, GitHub Apps, OAuth, and more.
103 | - **Pagination & Error Handling**: Handles pagination and common error scenarios out of the box.
104 | - **Extendable**: Supports plugins and custom hooks for advanced use cases[2].
105 | 
106 | ## How to Use Octokit for GitHub Issue Export
107 | 
108 | Install Octokit in your Node.js project:
109 | 
110 | ```bash
111 | npm install @octokit/rest
112 | ```
113 | 
114 | Basic usage for creating and linking issues:
115 | 
116 | ```js
117 | const { Octokit } = require("@octokit/rest");
118 | 
119 | // Authenticate with a personal access token
120 | const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
121 | 
122 | // Create a new issue
123 | const { data: issue } = await octokit.issues.create({
124 |   owner: "owner",
125 |   repo: "repo_name",
126 |   title: "Exported from Task Master",
127 |   body: "This issue was created by Task Master. [Task ID: 123]"
128 | });
129 | 
130 | // Add a comment for bidirectional linking
131 | await octokit.issues.createComment({
132 |   owner: "owner",
133 |   repo: "repo_name",
134 |   issue_number: issue.number,
135 |   body: "Linked to Task Master task #123"
136 | });
137 | ```
138 | 
139 | ## Alternatives
140 | 
141 | - **node-github**: An older library, less maintained than Octokit, but still functional for basic API access[5].
142 | - **Raw HTTP Requests**: You can use `node-fetch` or `axios` to call the GitHub API directly, but you’ll need to handle authentication, pagination, and error handling yourself[3]. Octokit abstracts all of this for you.
143 | 
144 | ## Summary Table
145 | 
146 | | Library         | Language | API Coverage | Maintained | TypeScript | Docs/Support |
147 | |-----------------|----------|--------------|------------|------------|--------------|
148 | | Octokit         | Node.js  | Full         | Yes        | Yes        | Excellent    |
149 | | node-github     | Node.js  | Full         | No         | No         | Limited      |
150 | | Raw HTTP        | Node.js  | Full (manual)| N/A        | N/A        | N/A          |
151 | 
152 | **Recommendation:** Use Octokit for all GitHub API interactions in your Node.js project. It’s the official, most robust, and best-supported option for your use case[1][2].
153 | 
154 | 
155 | ---
156 | 
157 | *Generated by Task Master Research Command*  
158 | *Timestamp: 2025-06-14T21:20:00.561Z*
159 | 
```

--------------------------------------------------------------------------------
/apps/cli/src/commands/next.command.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview NextCommand using Commander's native class pattern
  3 |  * Extends Commander.Command for better integration with the framework
  4 |  */
  5 | 
  6 | import path from 'node:path';
  7 | import { type Task, type TmCore, createTmCore } from '@tm/core';
  8 | import type { StorageType } from '@tm/core';
  9 | import boxen from 'boxen';
 10 | import chalk from 'chalk';
 11 | import { Command } from 'commander';
 12 | import { displayTaskDetails } from '../ui/components/task-detail.component.js';
 13 | import { displayCommandHeader } from '../utils/display-helpers.js';
 14 | import { displayError } from '../utils/error-handler.js';
 15 | import { getProjectRoot } from '../utils/project-root.js';
 16 | 
 17 | /**
 18 |  * Options interface for the next command
 19 |  */
 20 | export interface NextCommandOptions {
 21 | 	tag?: string;
 22 | 	format?: 'text' | 'json';
 23 | 	silent?: boolean;
 24 | 	project?: string;
 25 | }
 26 | 
 27 | /**
 28 |  * Result type from next command
 29 |  */
 30 | export interface NextTaskResult {
 31 | 	task: Task | null;
 32 | 	found: boolean;
 33 | 	tag: string;
 34 | 	storageType: Exclude<StorageType, 'auto'>;
 35 | }
 36 | 
 37 | /**
 38 |  * NextCommand extending Commander's Command class
 39 |  * This is a thin presentation layer over @tm/core
 40 |  */
 41 | export class NextCommand extends Command {
 42 | 	private tmCore?: TmCore;
 43 | 	private lastResult?: NextTaskResult;
 44 | 
 45 | 	constructor(name?: string) {
 46 | 		super(name || 'next');
 47 | 
 48 | 		// Configure the command
 49 | 		this.description('Find the next available task to work on')
 50 | 			.option('-t, --tag <tag>', 'Filter by tag')
 51 | 			.option('-f, --format <format>', 'Output format (text, json)', 'text')
 52 | 			.option('--silent', 'Suppress output (useful for programmatic usage)')
 53 | 			.option(
 54 | 				'-p, --project <path>',
 55 | 				'Project root directory (auto-detected if not provided)'
 56 | 			)
 57 | 			.action(async (options: NextCommandOptions) => {
 58 | 				await this.executeCommand(options);
 59 | 			});
 60 | 	}
 61 | 
 62 | 	/**
 63 | 	 * Execute the next command
 64 | 	 */
 65 | 	private async executeCommand(options: NextCommandOptions): Promise<void> {
 66 | 		let hasError = false;
 67 | 		try {
 68 | 			// Validate options (throws on invalid options)
 69 | 			this.validateOptions(options);
 70 | 
 71 | 			// Initialize tm-core
 72 | 			await this.initializeCore(getProjectRoot(options.project));
 73 | 
 74 | 			// Get next task from core
 75 | 			const result = await this.getNextTask(options);
 76 | 
 77 | 			// Store result for programmatic access
 78 | 			this.setLastResult(result);
 79 | 
 80 | 			// Display results
 81 | 			if (!options.silent) {
 82 | 				this.displayResults(result, options);
 83 | 			}
 84 | 		} catch (error: any) {
 85 | 			hasError = true;
 86 | 			displayError(error, { skipExit: true });
 87 | 		} finally {
 88 | 			// Always clean up resources, even on error
 89 | 			await this.cleanup();
 90 | 		}
 91 | 
 92 | 		// Exit after cleanup completes
 93 | 		if (hasError) {
 94 | 			process.exit(1);
 95 | 		}
 96 | 	}
 97 | 
 98 | 	/**
 99 | 	 * Validate command options
100 | 	 */
101 | 	private validateOptions(options: NextCommandOptions): void {
102 | 		// Validate format
103 | 		if (options.format && !['text', 'json'].includes(options.format)) {
104 | 			throw new Error(
105 | 				`Invalid format: ${options.format}. Valid formats are: text, json`
106 | 			);
107 | 		}
108 | 	}
109 | 
110 | 	/**
111 | 	 * Initialize TmCore
112 | 	 */
113 | 	private async initializeCore(projectRoot: string): Promise<void> {
114 | 		if (!this.tmCore) {
115 | 			const resolved = path.resolve(projectRoot);
116 | 			this.tmCore = await createTmCore({ projectPath: resolved });
117 | 		}
118 | 	}
119 | 
120 | 	/**
121 | 	 * Get next task from tm-core
122 | 	 */
123 | 	private async getNextTask(
124 | 		options: NextCommandOptions
125 | 	): Promise<NextTaskResult> {
126 | 		if (!this.tmCore) {
127 | 			throw new Error('TmCore not initialized');
128 | 		}
129 | 
130 | 		// Call tm-core to get next task
131 | 		const task = await this.tmCore.tasks.getNext(options.tag);
132 | 
133 | 		// Get storage type and active tag
134 | 		const storageType = this.tmCore.tasks.getStorageType();
135 | 
136 | 		const activeTag = options.tag || this.tmCore.config.getActiveTag();
137 | 
138 | 		return {
139 | 			task,
140 | 			found: task !== null,
141 | 			tag: activeTag,
142 | 			storageType
143 | 		};
144 | 	}
145 | 
146 | 	/**
147 | 	 * Display results based on format
148 | 	 */
149 | 	private displayResults(
150 | 		result: NextTaskResult,
151 | 		options: NextCommandOptions
152 | 	): void {
153 | 		const format = options.format || 'text';
154 | 
155 | 		switch (format) {
156 | 			case 'json':
157 | 				this.displayJson(result);
158 | 				break;
159 | 
160 | 			case 'text':
161 | 			default:
162 | 				this.displayText(result);
163 | 				break;
164 | 		}
165 | 	}
166 | 
167 | 	/**
168 | 	 * Display in JSON format
169 | 	 */
170 | 	private displayJson(result: NextTaskResult): void {
171 | 		console.log(JSON.stringify(result, null, 2));
172 | 	}
173 | 
174 | 	/**
175 | 	 * Display in text format
176 | 	 */
177 | 	private displayText(result: NextTaskResult): void {
178 | 		// Display header with storage info
179 | 		displayCommandHeader(this.tmCore, {
180 | 			tag: result.tag || 'master',
181 | 			storageType: result.storageType
182 | 		});
183 | 
184 | 		if (!result.found || !result.task) {
185 | 			// No next task available
186 | 			console.log(
187 | 				boxen(
188 | 					chalk.yellow(
189 | 						'No tasks available to work on. All tasks are either completed, blocked by dependencies, or in progress.'
190 | 					),
191 | 					{
192 | 						padding: 1,
193 | 						borderStyle: 'round',
194 | 						borderColor: 'yellow',
195 | 						title: '⚠️ NO TASKS AVAILABLE ⚠️',
196 | 						titleAlignment: 'center'
197 | 					}
198 | 				)
199 | 			);
200 | 			console.log(
201 | 				`\n${chalk.dim('Tip: Try')} ${chalk.cyan('task-master list --status pending')} ${chalk.dim('to see all pending tasks')}`
202 | 			);
203 | 			return;
204 | 		}
205 | 
206 | 		const task = result.task;
207 | 
208 | 		// Display the task details using the same component as 'show' command
209 | 		// with a custom header indicating this is the next task
210 | 		const customHeader = `Next Task: #${task.id} - ${task.title}`;
211 | 		displayTaskDetails(task, {
212 | 			customHeader,
213 | 			headerColor: 'green',
214 | 			showSuggestedActions: true,
215 | 			storageType: result.storageType
216 | 		});
217 | 	}
218 | 
219 | 	/**
220 | 	 * Set the last result for programmatic access
221 | 	 */
222 | 	private setLastResult(result: NextTaskResult): void {
223 | 		this.lastResult = result;
224 | 	}
225 | 
226 | 	/**
227 | 	 * Get the last result (for programmatic usage)
228 | 	 */
229 | 	getLastResult(): NextTaskResult | undefined {
230 | 		return this.lastResult;
231 | 	}
232 | 
233 | 	/**
234 | 	 * Clean up resources
235 | 	 */
236 | 	async cleanup(): Promise<void> {
237 | 		if (this.tmCore) {
238 | 			this.tmCore = undefined;
239 | 		}
240 | 	}
241 | 
242 | 	/**
243 | 	 * Register this command on an existing program
244 | 	 */
245 | 	static register(program: Command, name?: string): NextCommand {
246 | 		const nextCommand = new NextCommand(name);
247 | 		program.addCommand(nextCommand);
248 | 		return nextCommand;
249 | 	}
250 | }
251 | 
```

--------------------------------------------------------------------------------
/tests/unit/scripts/modules/task-manager/update-subtask-by-id.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { jest } from '@jest/globals';
  2 | 
  3 | // Provide fs mock early so existsSync can be stubbed
  4 | jest.unstable_mockModule('fs', () => {
  5 | 	const mockFs = {
  6 | 		existsSync: jest.fn(() => true),
  7 | 		writeFileSync: jest.fn(),
  8 | 		readFileSync: jest.fn(),
  9 | 		unlinkSync: jest.fn()
 10 | 	};
 11 | 	return { default: mockFs, ...mockFs };
 12 | });
 13 | 
 14 | // --- Mock dependencies ---
 15 | jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
 16 | 	readJSON: jest.fn(),
 17 | 	writeJSON: jest.fn(),
 18 | 	log: jest.fn(),
 19 | 	isSilentMode: jest.fn(() => false),
 20 | 	findProjectRoot: jest.fn(() => '/project'),
 21 | 	flattenTasksWithSubtasks: jest.fn(() => []),
 22 | 	truncate: jest.fn((t) => t),
 23 | 	isEmpty: jest.fn(() => false),
 24 | 	resolveEnvVariable: jest.fn(),
 25 | 	findTaskById: jest.fn(),
 26 | 	getCurrentTag: jest.fn(() => 'master'),
 27 | 	resolveTag: jest.fn(() => 'master'),
 28 | 	addComplexityToTask: jest.fn((task, complexity) => ({ ...task, complexity })),
 29 | 	getTasksForTag: jest.fn((data, tag) => data[tag]?.tasks || []),
 30 | 	setTasksForTag: jest.fn(),
 31 | 	ensureTagMetadata: jest.fn((tagObj) => tagObj)
 32 | }));
 33 | 
 34 | jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
 35 | 	displayBanner: jest.fn(),
 36 | 	getStatusWithColor: jest.fn((s) => s),
 37 | 	startLoadingIndicator: jest.fn(() => ({ stop: jest.fn() })),
 38 | 	stopLoadingIndicator: jest.fn(),
 39 | 	succeedLoadingIndicator: jest.fn(),
 40 | 	failLoadingIndicator: jest.fn(),
 41 | 	warnLoadingIndicator: jest.fn(),
 42 | 	infoLoadingIndicator: jest.fn(),
 43 | 	displayAiUsageSummary: jest.fn(),
 44 | 	displayContextAnalysis: jest.fn()
 45 | }));
 46 | 
 47 | jest.unstable_mockModule(
 48 | 	'../../../../../scripts/modules/task-manager/generate-task-files.js',
 49 | 	() => ({
 50 | 		default: jest.fn().mockResolvedValue()
 51 | 	})
 52 | );
 53 | 
 54 | jest.unstable_mockModule(
 55 | 	'../../../../../scripts/modules/ai-services-unified.js',
 56 | 	() => ({
 57 | 		generateTextService: jest
 58 | 			.fn()
 59 | 			.mockResolvedValue({ mainResult: { content: '' }, telemetryData: {} })
 60 | 	})
 61 | );
 62 | 
 63 | jest.unstable_mockModule(
 64 | 	'../../../../../scripts/modules/config-manager.js',
 65 | 	() => ({
 66 | 		getDebugFlag: jest.fn(() => false),
 67 | 		hasCodebaseAnalysis: jest.fn(() => false)
 68 | 	})
 69 | );
 70 | 
 71 | jest.unstable_mockModule(
 72 | 	'../../../../../scripts/modules/prompt-manager.js',
 73 | 	() => ({
 74 | 		default: jest.fn().mockReturnValue({
 75 | 			loadPrompt: jest.fn().mockReturnValue('Update the subtask')
 76 | 		}),
 77 | 		getPromptManager: jest.fn().mockReturnValue({
 78 | 			loadPrompt: jest.fn().mockReturnValue('Update the subtask')
 79 | 		})
 80 | 	})
 81 | );
 82 | 
 83 | jest.unstable_mockModule(
 84 | 	'../../../../../scripts/modules/utils/contextGatherer.js',
 85 | 	() => ({
 86 | 		ContextGatherer: jest.fn().mockImplementation(() => ({
 87 | 			gather: jest.fn().mockReturnValue({
 88 | 				fullContext: '',
 89 | 				summary: ''
 90 | 			})
 91 | 		}))
 92 | 	})
 93 | );
 94 | 
 95 | // Mock @tm/bridge module
 96 | jest.unstable_mockModule('@tm/bridge', () => ({
 97 | 	tryUpdateViaRemote: jest.fn().mockResolvedValue(null)
 98 | }));
 99 | 
100 | // Mock bridge-utils module
101 | jest.unstable_mockModule(
102 | 	'../../../../../scripts/modules/bridge-utils.js',
103 | 	() => ({
104 | 		createBridgeLogger: jest.fn(() => ({
105 | 			logger: {
106 | 				info: jest.fn(),
107 | 				warn: jest.fn(),
108 | 				error: jest.fn(),
109 | 				debug: jest.fn()
110 | 			},
111 | 			report: jest.fn(),
112 | 			isMCP: false
113 | 		}))
114 | 	})
115 | );
116 | 
117 | // Mock fuzzyTaskSearch module
118 | jest.unstable_mockModule(
119 | 	'../../../../../scripts/modules/utils/fuzzyTaskSearch.js',
120 | 	() => ({
121 | 		FuzzyTaskSearch: jest.fn().mockImplementation(() => ({
122 | 			search: jest.fn().mockReturnValue([])
123 | 		}))
124 | 	})
125 | );
126 | 
127 | // Import mocked utils to leverage mocks later
128 | const { readJSON, log } = await import(
129 | 	'../../../../../scripts/modules/utils.js'
130 | );
131 | 
132 | // Import function under test
133 | const { default: updateSubtaskById } = await import(
134 | 	'../../../../../scripts/modules/task-manager/update-subtask-by-id.js'
135 | );
136 | 
137 | describe('updateSubtaskById validation', () => {
138 | 	beforeEach(() => {
139 | 		jest.clearAllMocks();
140 | 		jest.spyOn(process, 'exit').mockImplementation(() => {
141 | 			throw new Error('process.exit called');
142 | 		});
143 | 	});
144 | 
145 | 	test('throws error on invalid subtask id format', async () => {
146 | 		await expect(
147 | 			updateSubtaskById(
148 | 				'tasks/tasks.json',
149 | 				'invalid',
150 | 				'my prompt',
151 | 				false,
152 | 				{
153 | 					tag: 'master'
154 | 				},
155 | 				'json'
156 | 			)
157 | 		).rejects.toThrow('Invalid subtask ID format');
158 | 	});
159 | 
160 | 	test('throws error when prompt is empty', async () => {
161 | 		await expect(
162 | 			updateSubtaskById(
163 | 				'tasks/tasks.json',
164 | 				'1.1',
165 | 				'',
166 | 				false,
167 | 				{ tag: 'master' },
168 | 				'json'
169 | 			)
170 | 		).rejects.toThrow('Prompt cannot be empty');
171 | 	});
172 | 
173 | 	test('throws error if tasks file does not exist', async () => {
174 | 		// Mock fs.existsSync to return false via jest.spyOn (dynamic import of fs)
175 | 		const fs = await import('fs');
176 | 		fs.existsSync.mockReturnValue(false);
177 | 		await expect(
178 | 			updateSubtaskById(
179 | 				'tasks/tasks.json',
180 | 				'1.1',
181 | 				'prompt',
182 | 				false,
183 | 				{
184 | 					tag: 'master'
185 | 				},
186 | 				'json'
187 | 			)
188 | 		).rejects.toThrow('Tasks file not found');
189 | 	});
190 | 
191 | 	test('throws error if parent task missing', async () => {
192 | 		// Mock existsSync true
193 | 		const fs = await import('fs');
194 | 		fs.existsSync.mockReturnValue(true);
195 | 		// readJSON returns tasks without parent id 1
196 | 		readJSON.mockReturnValue({ tag: 'master', tasks: [] });
197 | 		await expect(
198 | 			updateSubtaskById(
199 | 				'tasks/tasks.json',
200 | 				'1.1',
201 | 				'prompt',
202 | 				false,
203 | 				{
204 | 					tag: 'master'
205 | 				},
206 | 				'json'
207 | 			)
208 | 		).rejects.toThrow('Parent task with ID 1 not found');
209 | 		// log called with error level
210 | 		expect(log).toHaveBeenCalled();
211 | 	});
212 | 
213 | 	test('successfully updates subtask with valid inputs', async () => {
214 | 		const fs = await import('fs');
215 | 		const { writeJSON } = await import(
216 | 			'../../../../../scripts/modules/utils.js'
217 | 		);
218 | 
219 | 		fs.existsSync.mockReturnValue(true);
220 | 		readJSON.mockReturnValue({
221 | 			tag: 'master',
222 | 			tasks: [
223 | 				{
224 | 					id: 1,
225 | 					title: 'Parent Task',
226 | 					subtasks: [{ id: 1, title: 'Original subtask', status: 'pending' }]
227 | 				}
228 | 			]
229 | 		});
230 | 
231 | 		// updateSubtaskById doesn't return a value on success, it just executes
232 | 		await expect(
233 | 			updateSubtaskById(
234 | 				'tasks/tasks.json',
235 | 				'1.1',
236 | 				'Update this subtask',
237 | 				false,
238 | 				{ tag: 'master' },
239 | 				'json'
240 | 			)
241 | 		).resolves.not.toThrow();
242 | 
243 | 		expect(writeJSON).toHaveBeenCalled();
244 | 	});
245 | });
246 | 
```

--------------------------------------------------------------------------------
/apps/extension/src/webview/hooks/useVSCodeMessages.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Hook for handling VS Code messages
  3 |  */
  4 | 
  5 | import { useEffect, useCallback, useRef } from 'react';
  6 | import type { AppState, AppAction } from '../types';
  7 | import { createToast } from '../utils/toast';
  8 | import { REQUEST_TIMEOUT } from '../constants';
  9 | 
 10 | interface PendingRequest {
 11 | 	resolve: Function;
 12 | 	reject: Function;
 13 | 	timeout: NodeJS.Timeout;
 14 | }
 15 | 
 16 | let requestCounter = 0;
 17 | 
 18 | export const useVSCodeMessages = (
 19 | 	vscode: ReturnType<NonNullable<typeof window.acquireVsCodeApi>> | undefined,
 20 | 	state: AppState,
 21 | 	dispatch: React.Dispatch<AppAction>
 22 | ) => {
 23 | 	const pendingRequestsRef = useRef(new Map<string, PendingRequest>());
 24 | 
 25 | 	const sendMessage = useCallback(
 26 | 		(message: any): Promise<any> => {
 27 | 			if (!vscode) {
 28 | 				return Promise.reject(new Error('VS Code API not available'));
 29 | 			}
 30 | 
 31 | 			return new Promise((resolve, reject) => {
 32 | 				const requestId = `req_${++requestCounter}_${Date.now()}`;
 33 | 
 34 | 				const timeout = setTimeout(() => {
 35 | 					pendingRequestsRef.current.delete(requestId);
 36 | 					reject(new Error('Request timeout'));
 37 | 				}, REQUEST_TIMEOUT);
 38 | 
 39 | 				pendingRequestsRef.current.set(requestId, { resolve, reject, timeout });
 40 | 
 41 | 				vscode.postMessage({
 42 | 					...message,
 43 | 					requestId
 44 | 				});
 45 | 			});
 46 | 		},
 47 | 		[vscode]
 48 | 	);
 49 | 
 50 | 	useEffect(() => {
 51 | 		if (!vscode) return;
 52 | 
 53 | 		const handleMessage = (event: MessageEvent) => {
 54 | 			const message = event.data;
 55 | 			console.log('📥 Received message:', message.type, message);
 56 | 
 57 | 			// Handle request/response pattern
 58 | 			if (message.requestId) {
 59 | 				const pending = pendingRequestsRef.current.get(message.requestId);
 60 | 				if (pending) {
 61 | 					clearTimeout(pending.timeout);
 62 | 					pendingRequestsRef.current.delete(message.requestId);
 63 | 
 64 | 					if (message.type === 'response') {
 65 | 						// Check for explicit success field, default to true if data exists
 66 | 						const isSuccess =
 67 | 							message.success !== undefined
 68 | 								? message.success
 69 | 								: message.data !== undefined;
 70 | 						if (isSuccess) {
 71 | 							pending.resolve(message.data);
 72 | 						} else {
 73 | 							pending.reject(new Error(message.error || 'Request failed'));
 74 | 						}
 75 | 					} else if (message.type === 'error') {
 76 | 						pending.reject(new Error(message.error || 'Request failed'));
 77 | 					}
 78 | 				}
 79 | 				return;
 80 | 			}
 81 | 
 82 | 			// Handle other message types
 83 | 			switch (message.type) {
 84 | 				case 'connectionStatus':
 85 | 					dispatch({
 86 | 						type: 'SET_CONNECTION_STATUS',
 87 | 						payload: {
 88 | 							isConnected: message.data?.isConnected || false,
 89 | 							status: message.data?.status || 'Unknown'
 90 | 						}
 91 | 					});
 92 | 					break;
 93 | 
 94 | 				case 'tasksData':
 95 | 					console.log('📋 Received tasks data:', message.data);
 96 | 					dispatch({ type: 'SET_TASKS', payload: message.data });
 97 | 					break;
 98 | 
 99 | 				case 'pollingStatus':
100 | 					dispatch({
101 | 						type: 'SET_POLLING_STATUS',
102 | 						payload: {
103 | 							isActive: message.isActive,
104 | 							errorCount: message.errorCount || 0
105 | 						}
106 | 					});
107 | 					break;
108 | 
109 | 				case 'pollingUpdate':
110 | 					console.log('🔄 Polling update received:', {
111 | 						tasksCount: message.data?.length,
112 | 						userInteracting: state.polling.isUserInteracting,
113 | 						offlineMode: state.polling.isOfflineMode
114 | 					});
115 | 
116 | 					if (
117 | 						!state.polling.isUserInteracting &&
118 | 						!state.polling.isOfflineMode
119 | 					) {
120 | 						dispatch({
121 | 							type: 'TASKS_UPDATED_FROM_POLLING',
122 | 							payload: message.data
123 | 						});
124 | 					}
125 | 					break;
126 | 
127 | 				case 'networkStatus':
128 | 					dispatch({
129 | 						type: 'SET_NETWORK_STATUS',
130 | 						payload: message.data
131 | 					});
132 | 					break;
133 | 
134 | 				case 'cachedTasks':
135 | 					console.log('📦 Received cached tasks:', message.data);
136 | 					dispatch({
137 | 						type: 'LOAD_CACHED_TASKS',
138 | 						payload: message.data
139 | 					});
140 | 					break;
141 | 
142 | 				case 'errorNotification':
143 | 					handleErrorNotification(message, dispatch);
144 | 					break;
145 | 
146 | 				case 'error':
147 | 					handleGeneralError(message, dispatch);
148 | 					break;
149 | 
150 | 				case 'reactError':
151 | 					console.log('🔥 React error reported to extension:', message);
152 | 					dispatch({
153 | 						type: 'ADD_TOAST',
154 | 						payload: createToast(
155 | 							'error',
156 | 							'UI Error',
157 | 							'A component error occurred. The extension may need to be reloaded.',
158 | 							10000
159 | 						)
160 | 					});
161 | 					break;
162 | 
163 | 				default:
164 | 					console.log('❓ Unknown message type:', message.type);
165 | 			}
166 | 		};
167 | 
168 | 		window.addEventListener('message', handleMessage);
169 | 		return () => window.removeEventListener('message', handleMessage);
170 | 	}, [vscode, state.polling, dispatch]);
171 | 
172 | 	return { sendMessage };
173 | };
174 | 
175 | function handleErrorNotification(
176 | 	message: any,
177 | 	dispatch: React.Dispatch<AppAction>
178 | ) {
179 | 	console.log('📨 Error notification received:', message);
180 | 	const errorData = message.data;
181 | 
182 | 	// Map severity to toast type
183 | 	let toastType: 'error' | 'warning' | 'info' = 'error';
184 | 	if (errorData.severity === 'high' || errorData.severity === 'critical') {
185 | 		toastType = 'error';
186 | 	} else if (errorData.severity === 'medium') {
187 | 		toastType = 'warning';
188 | 	} else {
189 | 		toastType = 'info';
190 | 	}
191 | 
192 | 	// Create appropriate toast based on error category
193 | 	const title =
194 | 		errorData.category === 'network'
195 | 			? 'Network Error'
196 | 			: errorData.category === 'mcp_connection'
197 | 				? 'Connection Error'
198 | 				: errorData.category === 'task_loading'
199 | 					? 'Task Loading Error'
200 | 					: errorData.category === 'ui_rendering'
201 | 						? 'UI Error'
202 | 						: 'Error';
203 | 
204 | 	dispatch({
205 | 		type: 'ADD_TOAST',
206 | 		payload: createToast(
207 | 			toastType,
208 | 			title,
209 | 			errorData.message,
210 | 			errorData.duration || (toastType === 'error' ? 8000 : 5000)
211 | 		)
212 | 	});
213 | }
214 | 
215 | function handleGeneralError(message: any, dispatch: React.Dispatch<AppAction>) {
216 | 	console.log('❌ General error from extension:', message);
217 | 	const errorTitle =
218 | 		message.errorType === 'connection' ? 'Connection Error' : 'Error';
219 | 	const errorMessage = message.error || 'An unknown error occurred';
220 | 
221 | 	dispatch({
222 | 		type: 'SET_ERROR',
223 | 		payload: errorMessage
224 | 	});
225 | 
226 | 	dispatch({
227 | 		type: 'ADD_TOAST',
228 | 		payload: createToast('error', errorTitle, errorMessage, 8000)
229 | 	});
230 | 
231 | 	// Set offline mode for connection errors
232 | 	if (message.errorType === 'connection') {
233 | 		dispatch({
234 | 			type: 'SET_NETWORK_STATUS',
235 | 			payload: {
236 | 				isOfflineMode: true,
237 | 				connectionStatus: 'offline',
238 | 				reconnectAttempts: 0
239 | 			}
240 | 		});
241 | 	}
242 | }
243 | 
```

--------------------------------------------------------------------------------
/packages/tm-core/src/tm-core.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview TmCore - Unified facade for all Task Master functionality
  3 |  * This is the ONLY entry point for using tm-core
  4 |  */
  5 | 
  6 | import path from 'node:path';
  7 | import { AuthDomain } from './modules/auth/auth-domain.js';
  8 | import { ConfigDomain } from './modules/config/config-domain.js';
  9 | import { ConfigManager } from './modules/config/managers/config-manager.js';
 10 | import { GitDomain } from './modules/git/git-domain.js';
 11 | import { IntegrationDomain } from './modules/integration/integration-domain.js';
 12 | import { TasksDomain } from './modules/tasks/tasks-domain.js';
 13 | import { WorkflowDomain } from './modules/workflow/workflow-domain.js';
 14 | 
 15 | import {
 16 | 	ERROR_CODES,
 17 | 	TaskMasterError
 18 | } from './common/errors/task-master-error.js';
 19 | import type { IConfiguration } from './common/interfaces/configuration.interface.js';
 20 | import {
 21 | 	type Logger,
 22 | 	type LoggerConfig,
 23 | 	createLogger
 24 | } from './common/logger/index.js';
 25 | 
 26 | /**
 27 |  * Options for creating TmCore instance
 28 |  */
 29 | export interface TmCoreOptions {
 30 | 	/** Absolute path to project root */
 31 | 	projectPath: string;
 32 | 	/** Optional configuration overrides */
 33 | 	configuration?: Partial<IConfiguration>;
 34 | 	/** Optional logger configuration for MCP integration and debugging */
 35 | 	loggerConfig?: LoggerConfig;
 36 | }
 37 | 
 38 | /**
 39 |  * TmCore - Unified facade providing access to all Task Master domains
 40 |  *
 41 |  * @example Basic usage
 42 |  * ```typescript
 43 |  * const tmcore = await createTmCore({ projectPath: process.cwd() });
 44 |  *
 45 |  * // Access any domain
 46 |  * await tmcore.auth.authenticateWithOAuth();
 47 |  * const tasks = await tmcore.tasks.list();
 48 |  * await tmcore.workflow.start({ taskId: '1' });
 49 |  * await tmcore.git.commit('feat: add feature');
 50 |  * const modelConfig = tmcore.config.getModelConfig();
 51 |  * await tmcore.integration.exportTasks({ ... });
 52 |  * ```
 53 |  *
 54 |  * @example MCP integration with logging
 55 |  * ```typescript
 56 |  * import { LogLevel } from '@tm/core/logger';
 57 |  *
 58 |  * // In MCP tool execute function
 59 |  * async function execute(args, log) {
 60 |  *   const tmcore = await createTmCore({
 61 |  *     projectPath: args.projectRoot,
 62 |  *     loggerConfig: {
 63 |  *       level: LogLevel.INFO,
 64 |  *       mcpMode: true,
 65 |  *       logCallback: log  // MCP log function
 66 |  *     }
 67 |  *   });
 68 |  *
 69 |  *   // All internal logging will now be sent to MCP
 70 |  *   const tasks = await tmcore.tasks.list();
 71 |  *
 72 |  *   // You can also log custom messages
 73 |  *   tmcore.logger.info('Operation completed');
 74 |  * }
 75 |  * ```
 76 |  */
 77 | export class TmCore {
 78 | 	// Core infrastructure
 79 | 	private readonly _projectPath: string;
 80 | 	private _configManager!: ConfigManager;
 81 | 	private _logger!: Logger;
 82 | 
 83 | 	// Private writable properties
 84 | 	private _tasks!: TasksDomain;
 85 | 	private _auth!: AuthDomain;
 86 | 	private _workflow!: WorkflowDomain;
 87 | 	private _git!: GitDomain;
 88 | 	private _config!: ConfigDomain;
 89 | 	private _integration!: IntegrationDomain;
 90 | 
 91 | 	// Public readonly getters
 92 | 	get tasks(): TasksDomain {
 93 | 		return this._tasks;
 94 | 	}
 95 | 	get auth(): AuthDomain {
 96 | 		return this._auth;
 97 | 	}
 98 | 	get workflow(): WorkflowDomain {
 99 | 		return this._workflow;
100 | 	}
101 | 	get git(): GitDomain {
102 | 		return this._git;
103 | 	}
104 | 	get config(): ConfigDomain {
105 | 		return this._config;
106 | 	}
107 | 	get integration(): IntegrationDomain {
108 | 		return this._integration;
109 | 	}
110 | 	get logger(): Logger {
111 | 		return this._logger;
112 | 	}
113 | 
114 | 	/**
115 | 	 * Create and initialize a new TmCore instance
116 | 	 * This is the ONLY way to create TmCore
117 | 	 *
118 | 	 * @param options - Configuration options
119 | 	 * @returns Fully initialized TmCore instance
120 | 	 */
121 | 	static async create(options: TmCoreOptions): Promise<TmCore> {
122 | 		const instance = new TmCore(options);
123 | 		await instance.initialize();
124 | 		return instance;
125 | 	}
126 | 
127 | 	private _options: TmCoreOptions;
128 | 
129 | 	/**
130 | 	 * Private constructor - use TmCore.create() instead
131 | 	 * This ensures TmCore is always properly initialized
132 | 	 */
133 | 	private constructor(options: TmCoreOptions) {
134 | 		if (!options.projectPath) {
135 | 			throw new TaskMasterError(
136 | 				'Project path is required',
137 | 				ERROR_CODES.MISSING_CONFIGURATION
138 | 			);
139 | 		}
140 | 
141 | 		// Validate that projectPath is absolute
142 | 		if (!path.isAbsolute(options.projectPath)) {
143 | 			throw new TaskMasterError(
144 | 				`Project path must be an absolute path, received: "${options.projectPath}"`,
145 | 				ERROR_CODES.INVALID_INPUT
146 | 			);
147 | 		}
148 | 
149 | 		// Normalize the path
150 | 		this._projectPath = path.resolve(options.projectPath);
151 | 		this._options = options;
152 | 		// Domain facades will be initialized in initialize()
153 | 	}
154 | 
155 | 	/**
156 | 	 * Initialize the TmCore instance
157 | 	 * Private - only called by the factory method
158 | 	 */
159 | 	private async initialize(): Promise<void> {
160 | 		try {
161 | 			// Initialize logger first (before anything else that might log)
162 | 			this._logger = createLogger(this._options.loggerConfig);
163 | 
164 | 			// Create config manager
165 | 			this._configManager = await ConfigManager.create(this._projectPath);
166 | 
167 | 			// Apply configuration overrides if provided
168 | 			if (this._options.configuration) {
169 | 				await this._configManager.updateConfig(this._options.configuration);
170 | 			}
171 | 
172 | 			// Initialize domain facades
173 | 			this._auth = new AuthDomain();
174 | 			this._tasks = new TasksDomain(this._configManager, this._auth);
175 | 			this._workflow = new WorkflowDomain(this._configManager);
176 | 			this._git = new GitDomain(this._projectPath);
177 | 			this._config = new ConfigDomain(this._configManager);
178 | 			this._integration = new IntegrationDomain(this._configManager);
179 | 
180 | 			// Initialize domains that need async setup
181 | 			await this._tasks.initialize();
182 | 
183 | 			// Log successful initialization
184 | 			this._logger.info('TmCore initialized successfully');
185 | 		} catch (error) {
186 | 			// Log error if logger is available
187 | 			if (this._logger) {
188 | 				this._logger.error('Failed to initialize TmCore:', error);
189 | 			}
190 | 
191 | 			throw new TaskMasterError(
192 | 				'Failed to initialize TmCore',
193 | 				ERROR_CODES.INTERNAL_ERROR,
194 | 				{ operation: 'initialize' },
195 | 				error as Error
196 | 			);
197 | 		}
198 | 	}
199 | 
200 | 	/**
201 | 	 * Get project root path
202 | 	 */
203 | 	get projectPath(): string {
204 | 		return this._projectPath;
205 | 	}
206 | }
207 | 
208 | /**
209 |  * Factory function to create a new TmCore instance
210 |  * This is the recommended way to create TmCore
211 |  *
212 |  * @param options - Configuration options
213 |  * @returns Fully initialized TmCore instance
214 |  */
215 | export async function createTmCore(options: TmCoreOptions): Promise<TmCore> {
216 | 	return TmCore.create(options);
217 | }
218 | 
```

--------------------------------------------------------------------------------
/docs/migration-guide.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Migration Guide: New .taskmaster Directory Structure
  2 | 
  3 | ## Overview
  4 | 
  5 | Task Master v0.16.0 introduces a new `.taskmaster/` directory structure to keep your project directories clean and organized. This guide explains the benefits of the new structure and how to migrate existing projects.
  6 | 
  7 | ## What's New
  8 | 
  9 | ### Before (Legacy Structure)
 10 | 
 11 | ```
 12 | your-project/
 13 | ├── tasks/                    # Task files
 14 | │   ├── tasks.json
 15 | │   ├── task-1.txt
 16 | │   └── task-2.txt
 17 | ├── scripts/                  # PRD and reports
 18 | │   ├── prd.txt
 19 | │   ├── example_prd.txt
 20 | │   └── task-complexity-report.json
 21 | ├── .taskmasterconfig         # Configuration
 22 | └── ... (your project files)
 23 | ```
 24 | 
 25 | ### After (New Structure)
 26 | 
 27 | ```
 28 | your-project/
 29 | ├── .taskmaster/              # Consolidated Task Master files
 30 | │   ├── config.json          # Configuration (was .taskmasterconfig)
 31 | │   ├── tasks/               # Task files
 32 | │   │   ├── tasks.json
 33 | │   │   ├── task-1.txt
 34 | │   │   └── task-2.txt
 35 | │   ├── docs/                # Project documentation
 36 | │   │   └── prd.txt
 37 | │   ├── reports/             # Generated reports
 38 | │   │   └── task-complexity-report.json
 39 | │   └── templates/           # Example/template files
 40 | │       └── example_prd.txt
 41 | └── ... (your project files)
 42 | ```
 43 | 
 44 | ## Benefits of the New Structure
 45 | 
 46 | ✅ **Cleaner Project Root**: No more scattered Task Master files  
 47 | ✅ **Better Organization**: Logical separation of tasks, docs, reports, and templates  
 48 | ✅ **Hidden by Default**: `.taskmaster/` directory is hidden from most file browsers  
 49 | ✅ **Future-Proof**: Centralized location for Task Master extensions  
 50 | ✅ **Backward Compatible**: Existing projects continue to work until migrated
 51 | 
 52 | ## Migration Options
 53 | 
 54 | ### Option 1: Automatic Migration (Recommended)
 55 | 
 56 | Task Master provides a built-in migration command that handles everything automatically:
 57 | 
 58 | #### CLI Migration
 59 | 
 60 | ```bash
 61 | # Dry run to see what would be migrated
 62 | task-master migrate --dry-run
 63 | 
 64 | # Perform the migration with backup
 65 | task-master migrate --backup
 66 | 
 67 | # Force migration (overwrites existing files)
 68 | task-master migrate --force
 69 | 
 70 | # Clean up legacy files after migration
 71 | task-master migrate --cleanup
 72 | ```
 73 | 
 74 | #### MCP Migration (Cursor/AI Editors)
 75 | 
 76 | Ask your AI assistant:
 77 | 
 78 | ```
 79 | Please migrate my Task Master project to the new .taskmaster directory structure
 80 | ```
 81 | 
 82 | ### Option 2: Manual Migration
 83 | 
 84 | If you prefer to migrate manually:
 85 | 
 86 | 1. **Create the new directory structure:**
 87 | 
 88 |    ```bash
 89 |    mkdir -p .taskmaster/{tasks,docs,reports,templates}
 90 |    ```
 91 | 
 92 | 2. **Move your files:**
 93 | 
 94 |    ```bash
 95 |    # Move tasks
 96 |    mv tasks/* .taskmaster/tasks/
 97 | 
 98 |    # Move configuration
 99 |    mv .taskmasterconfig .taskmaster/config.json
100 | 
101 |    # Move PRD and documentation
102 |    mv scripts/prd.txt .taskmaster/docs/
103 |    mv scripts/example_prd.txt .taskmaster/templates/
104 | 
105 |    # Move reports (if they exist)
106 |    mv scripts/task-complexity-report.json .taskmaster/reports/ 2>/dev/null || true
107 |    ```
108 | 
109 | 3. **Clean up empty directories:**
110 |    ```bash
111 |    rmdir tasks scripts 2>/dev/null || true
112 |    ```
113 | 
114 | ## What Gets Migrated
115 | 
116 | The migration process handles these file types:
117 | 
118 | ### Tasks Directory → `.taskmaster/tasks/`
119 | 
120 | - `tasks.json`
121 | - Individual task text files (`.txt`)
122 | 
123 | ### Scripts Directory → Multiple Destinations
124 | 
125 | - **PRD files** → `.taskmaster/docs/`
126 |   - `prd.txt`, `requirements.txt`, etc.
127 | - **Example/Template files** → `.taskmaster/templates/`
128 |   - `example_prd.txt`, template files
129 | - **Reports** → `.taskmaster/reports/`
130 |   - `task-complexity-report.json`
131 | 
132 | ### Configuration
133 | 
134 | - `.taskmasterconfig` → `.taskmaster/config.json`
135 | 
136 | ## After Migration
137 | 
138 | Once migrated, Task Master will:
139 | 
140 | ✅ **Automatically use** the new directory structure  
141 | ✅ **Show deprecation warnings** when legacy files are detected  
142 | ✅ **Create new files** in the proper locations  
143 | ✅ **Fall back gracefully** to legacy locations if new ones don't exist
144 | 
145 | ### Verification
146 | 
147 | After migration, verify everything works:
148 | 
149 | 1. **List your tasks:**
150 | 
151 |    ```bash
152 |    task-master list
153 |    ```
154 | 
155 | 2. **Check your configuration:**
156 | 
157 |    ```bash
158 |    task-master models
159 |    ```
160 | 
161 | 3. **Generate new task files:**
162 |    ```bash
163 |    task-master generate
164 |    ```
165 | 
166 | ## Troubleshooting
167 | 
168 | ### Migration Issues
169 | 
170 | **Q: Migration says "no files to migrate"**  
171 | A: Your project may already be using the new structure or have no Task Master files to migrate.
172 | 
173 | **Q: Migration fails with permission errors**  
174 | A: Ensure you have write permissions in your project directory.
175 | 
176 | **Q: Some files weren't migrated**  
177 | A: Check the migration output - some files may not match the expected patterns. You can migrate these manually.
178 | 
179 | ### Working with Legacy Projects
180 | 
181 | If you're working with an older project that hasn't been migrated:
182 | 
183 | - Task Master will continue to work with the old structure
184 | - You'll see deprecation warnings in the output
185 | - New files will still be created in legacy locations
186 | - Use the migration command when ready to upgrade
187 | 
188 | ### New Project Initialization
189 | 
190 | New projects automatically use the new structure:
191 | 
192 | ```bash
193 | task-master init  # Creates .taskmaster/ structure
194 | ```
195 | 
196 | ## Path Changes for Developers
197 | 
198 | If you're developing tools or scripts that interact with Task Master files:
199 | 
200 | ### Configuration File
201 | 
202 | - **Old:** `.taskmasterconfig`
203 | - **New:** `.taskmaster/config.json`
204 | - **Fallback:** Task Master checks both locations
205 | 
206 | ### Tasks File
207 | 
208 | - **Old:** `tasks/tasks.json`
209 | - **New:** `.taskmaster/tasks/tasks.json`
210 | - **Fallback:** Task Master checks both locations
211 | 
212 | ### Reports
213 | 
214 | - **Old:** `scripts/task-complexity-report.json`
215 | - **New:** `.taskmaster/reports/task-complexity-report.json`
216 | - **Fallback:** Task Master checks both locations
217 | 
218 | ### PRD Files
219 | 
220 | - **Old:** `scripts/prd.txt`
221 | - **New:** `.taskmaster/docs/prd.txt`
222 | - **Fallback:** Task Master checks both locations
223 | 
224 | ## Need Help?
225 | 
226 | If you encounter issues during migration:
227 | 
228 | 1. **Check the logs:** Add `--debug` flag for detailed output
229 | 2. **Backup first:** Always use `--backup` option for safety
230 | 3. **Test with dry-run:** Use `--dry-run` to preview changes
231 | 4. **Ask for help:** Use our Discord community or GitHub issues
232 | 
233 | ---
234 | 
235 | _This migration guide applies to Task Master v0.15.x and later. For older versions, please upgrade to the latest version first._
236 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/parse-prd.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * parse-prd.js
  3 |  * Direct function implementation for parsing PRD documents
  4 |  */
  5 | 
  6 | import path from 'path';
  7 | import fs from 'fs';
  8 | import { parsePRD } from '../../../../scripts/modules/task-manager.js';
  9 | import {
 10 | 	enableSilentMode,
 11 | 	disableSilentMode,
 12 | 	isSilentMode
 13 | } from '../../../../scripts/modules/utils.js';
 14 | import { createLogWrapper } from '../../tools/utils.js';
 15 | import { getDefaultNumTasks } from '../../../../scripts/modules/config-manager.js';
 16 | import { resolvePrdPath, resolveProjectPath } from '../utils/path-utils.js';
 17 | import { TASKMASTER_TASKS_FILE } from '../../../../src/constants/paths.js';
 18 | 
 19 | /**
 20 |  * Direct function wrapper for parsing PRD documents and generating tasks.
 21 |  *
 22 |  * @param {Object} args - Command arguments containing projectRoot, input, output, numTasks options.
 23 |  * @param {string} args.input - Path to the input PRD file.
 24 |  * @param {string} args.output - Path to the output directory.
 25 |  * @param {string} args.numTasks - Number of tasks to generate.
 26 |  * @param {boolean} args.force - Whether to force parsing.
 27 |  * @param {boolean} args.append - Whether to append to the output file.
 28 |  * @param {boolean} args.research - Whether to use research mode.
 29 |  * @param {string} args.tag - Tag context for organizing tasks into separate task lists.
 30 |  * @param {Object} log - Logger object.
 31 |  * @param {Object} context - Context object containing session data.
 32 |  * @returns {Promise<Object>} - Result object with success status and data/error information.
 33 |  */
 34 | export async function parsePRDDirect(args, log, context = {}) {
 35 | 	const { session, reportProgress } = context;
 36 | 	// Extract projectRoot from args
 37 | 	const {
 38 | 		input: inputArg,
 39 | 		output: outputArg,
 40 | 		numTasks: numTasksArg,
 41 | 		force,
 42 | 		append,
 43 | 		research,
 44 | 		projectRoot,
 45 | 		tag
 46 | 	} = args;
 47 | 
 48 | 	// Create the standard logger wrapper
 49 | 	const logWrapper = createLogWrapper(log);
 50 | 
 51 | 	// --- Input Validation and Path Resolution ---
 52 | 	if (!projectRoot) {
 53 | 		logWrapper.error('parsePRDDirect requires a projectRoot argument.');
 54 | 		return {
 55 | 			success: false,
 56 | 			error: {
 57 | 				code: 'MISSING_ARGUMENT',
 58 | 				message: 'projectRoot is required.'
 59 | 			}
 60 | 		};
 61 | 	}
 62 | 
 63 | 	// Resolve input path using path utilities
 64 | 	let inputPath;
 65 | 	if (inputArg) {
 66 | 		try {
 67 | 			inputPath = resolvePrdPath({ input: inputArg, projectRoot }, session);
 68 | 		} catch (error) {
 69 | 			logWrapper.error(`Error resolving PRD path: ${error.message}`);
 70 | 			return {
 71 | 				success: false,
 72 | 				error: { code: 'FILE_NOT_FOUND', message: error.message }
 73 | 			};
 74 | 		}
 75 | 	} else {
 76 | 		logWrapper.error('parsePRDDirect called without input path');
 77 | 		return {
 78 | 			success: false,
 79 | 			error: { code: 'MISSING_ARGUMENT', message: 'Input path is required' }
 80 | 		};
 81 | 	}
 82 | 
 83 | 	// Resolve output path - use new path utilities for default
 84 | 	const outputPath = outputArg
 85 | 		? path.isAbsolute(outputArg)
 86 | 			? outputArg
 87 | 			: path.resolve(projectRoot, outputArg)
 88 | 		: resolveProjectPath(TASKMASTER_TASKS_FILE, args) ||
 89 | 			path.resolve(projectRoot, TASKMASTER_TASKS_FILE);
 90 | 
 91 | 	// Check if input file exists
 92 | 	if (!fs.existsSync(inputPath)) {
 93 | 		const errorMsg = `Input PRD file not found at resolved path: ${inputPath}`;
 94 | 		logWrapper.error(errorMsg);
 95 | 		return {
 96 | 			success: false,
 97 | 			error: { code: 'FILE_NOT_FOUND', message: errorMsg }
 98 | 		};
 99 | 	}
100 | 
101 | 	const outputDir = path.dirname(outputPath);
102 | 	try {
103 | 		if (!fs.existsSync(outputDir)) {
104 | 			logWrapper.info(`Creating output directory: ${outputDir}`);
105 | 			fs.mkdirSync(outputDir, { recursive: true });
106 | 		}
107 | 	} catch (error) {
108 | 		const errorMsg = `Failed to create output directory ${outputDir}: ${error.message}`;
109 | 		logWrapper.error(errorMsg);
110 | 		return {
111 | 			success: false,
112 | 			error: { code: 'DIRECTORY_CREATE_FAILED', message: errorMsg }
113 | 		};
114 | 	}
115 | 
116 | 	let numTasks = getDefaultNumTasks(projectRoot);
117 | 	if (numTasksArg) {
118 | 		numTasks =
119 | 			typeof numTasksArg === 'string' ? parseInt(numTasksArg, 10) : numTasksArg;
120 | 		if (Number.isNaN(numTasks) || numTasks < 0) {
121 | 			// Ensure positive number
122 | 			numTasks = getDefaultNumTasks(projectRoot); // Fallback to default if parsing fails or invalid
123 | 			logWrapper.warn(
124 | 				`Invalid numTasks value: ${numTasksArg}. Using default: ${numTasks}`
125 | 			);
126 | 		}
127 | 	}
128 | 
129 | 	if (append) {
130 | 		logWrapper.info('Append mode enabled.');
131 | 		if (force) {
132 | 			logWrapper.warn(
133 | 				'Both --force and --append flags were provided. --force takes precedence; append mode will be ignored.'
134 | 			);
135 | 		}
136 | 	}
137 | 
138 | 	if (research) {
139 | 		logWrapper.info(
140 | 			'Research mode enabled. Using Perplexity AI for enhanced PRD analysis.'
141 | 		);
142 | 	}
143 | 
144 | 	logWrapper.info(
145 | 		`Parsing PRD via direct function. Input: ${inputPath}, Output: ${outputPath}, NumTasks: ${numTasks}, Force: ${force}, Append: ${append}, Research: ${research}, ProjectRoot: ${projectRoot}`
146 | 	);
147 | 
148 | 	const wasSilent = isSilentMode();
149 | 	if (!wasSilent) {
150 | 		enableSilentMode();
151 | 	}
152 | 
153 | 	try {
154 | 		// Call the core parsePRD function
155 | 		const result = await parsePRD(
156 | 			inputPath,
157 | 			outputPath,
158 | 			numTasks,
159 | 			{
160 | 				session,
161 | 				mcpLog: logWrapper,
162 | 				projectRoot,
163 | 				tag,
164 | 				force,
165 | 				append,
166 | 				research,
167 | 				reportProgress,
168 | 				commandName: 'parse-prd',
169 | 				outputType: 'mcp'
170 | 			},
171 | 			'json'
172 | 		);
173 | 
174 | 		// Adjust check for the new return structure
175 | 		if (result && result.success) {
176 | 			const successMsg = `Successfully parsed PRD and generated tasks in ${result.tasksPath}`;
177 | 			logWrapper.success(successMsg);
178 | 			return {
179 | 				success: true,
180 | 				data: {
181 | 					message: successMsg,
182 | 					outputPath: result.tasksPath,
183 | 					telemetryData: result.telemetryData,
184 | 					tagInfo: result.tagInfo
185 | 				}
186 | 			};
187 | 		} else {
188 | 			// Handle case where core function didn't return expected success structure
189 | 			logWrapper.error(
190 | 				'Core parsePRD function did not return a successful structure.'
191 | 			);
192 | 			return {
193 | 				success: false,
194 | 				error: {
195 | 					code: 'CORE_FUNCTION_ERROR',
196 | 					message:
197 | 						result?.message ||
198 | 						'Core function failed to parse PRD or returned unexpected result.'
199 | 				}
200 | 			};
201 | 		}
202 | 	} catch (error) {
203 | 		logWrapper.error(`Error executing core parsePRD: ${error.message}`);
204 | 		return {
205 | 			success: false,
206 | 			error: {
207 | 				code: 'PARSE_PRD_CORE_ERROR',
208 | 				message: error.message || 'Unknown error parsing PRD'
209 | 			}
210 | 		};
211 | 	} finally {
212 | 		if (!wasSilent && isSilentMode()) {
213 | 			disableSilentMode();
214 | 		}
215 | 	}
216 | }
217 | 
```

--------------------------------------------------------------------------------
/tests/unit/profiles/rule-transformer-cline.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { jest } from '@jest/globals';
  2 | 
  3 | // Mock fs module before importing anything that uses it
  4 | jest.mock('fs', () => ({
  5 | 	readFileSync: jest.fn(),
  6 | 	writeFileSync: jest.fn(),
  7 | 	existsSync: jest.fn(),
  8 | 	mkdirSync: jest.fn()
  9 | }));
 10 | 
 11 | // Import modules after mocking
 12 | import fs from 'fs';
 13 | import { convertRuleToProfileRule } from '../../../src/utils/rule-transformer.js';
 14 | import { clineProfile } from '../../../src/profiles/cline.js';
 15 | 
 16 | describe('Cline Rule Transformer', () => {
 17 | 	// Set up spies on the mocked modules
 18 | 	const mockReadFileSync = jest.spyOn(fs, 'readFileSync');
 19 | 	const mockWriteFileSync = jest.spyOn(fs, 'writeFileSync');
 20 | 	const mockExistsSync = jest.spyOn(fs, 'existsSync');
 21 | 	const mockMkdirSync = jest.spyOn(fs, 'mkdirSync');
 22 | 	const mockConsoleError = jest
 23 | 		.spyOn(console, 'error')
 24 | 		.mockImplementation(() => {});
 25 | 
 26 | 	beforeEach(() => {
 27 | 		jest.clearAllMocks();
 28 | 		// Setup default mocks
 29 | 		mockReadFileSync.mockReturnValue('');
 30 | 		mockWriteFileSync.mockImplementation(() => {});
 31 | 		mockExistsSync.mockReturnValue(true);
 32 | 		mockMkdirSync.mockImplementation(() => {});
 33 | 	});
 34 | 
 35 | 	afterAll(() => {
 36 | 		jest.restoreAllMocks();
 37 | 	});
 38 | 
 39 | 	it('should correctly convert basic terms', () => {
 40 | 		const testContent = `---
 41 | description: Test Cursor rule for basic terms
 42 | globs: **/*
 43 | alwaysApply: true
 44 | ---
 45 | 
 46 | This is a Cursor rule that references cursor.so and uses the word Cursor multiple times.
 47 | Also has references to .mdc files.`;
 48 | 
 49 | 		// Mock file read to return our test content
 50 | 		mockReadFileSync.mockReturnValue(testContent);
 51 | 
 52 | 		// Call the actual function
 53 | 		const result = convertRuleToProfileRule(
 54 | 			'source.mdc',
 55 | 			'target.md',
 56 | 			clineProfile
 57 | 		);
 58 | 
 59 | 		// Verify the function succeeded
 60 | 		expect(result).toBe(true);
 61 | 
 62 | 		// Verify file operations were called correctly
 63 | 		expect(mockReadFileSync).toHaveBeenCalledWith('source.mdc', 'utf8');
 64 | 		expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
 65 | 
 66 | 		// Get the transformed content that was written
 67 | 		const writeCall = mockWriteFileSync.mock.calls[0];
 68 | 		const transformedContent = writeCall[1];
 69 | 
 70 | 		// Verify transformations
 71 | 		expect(transformedContent).toContain('Cline');
 72 | 		expect(transformedContent).toContain('cline.bot');
 73 | 		expect(transformedContent).toContain('.md');
 74 | 		expect(transformedContent).not.toContain('cursor.so');
 75 | 		expect(transformedContent).not.toContain('Cursor rule');
 76 | 	});
 77 | 
 78 | 	it('should correctly convert tool references', () => {
 79 | 		const testContent = `---
 80 | description: Test Cursor rule for tool references
 81 | globs: **/*
 82 | alwaysApply: true
 83 | ---
 84 | 
 85 | - Use the search tool to find code
 86 | - The edit_file tool lets you modify files
 87 | - run_command executes terminal commands
 88 | - use_mcp connects to external services`;
 89 | 
 90 | 		// Mock file read to return our test content
 91 | 		mockReadFileSync.mockReturnValue(testContent);
 92 | 
 93 | 		// Call the actual function
 94 | 		const result = convertRuleToProfileRule(
 95 | 			'source.mdc',
 96 | 			'target.md',
 97 | 			clineProfile
 98 | 		);
 99 | 
100 | 		// Verify the function succeeded
101 | 		expect(result).toBe(true);
102 | 
103 | 		// Get the transformed content that was written
104 | 		const writeCall = mockWriteFileSync.mock.calls[0];
105 | 		const transformedContent = writeCall[1];
106 | 
107 | 		// Verify transformations (Cline uses standard tool names, so no transformation)
108 | 		expect(transformedContent).toContain('search tool');
109 | 		expect(transformedContent).toContain('edit_file tool');
110 | 		expect(transformedContent).toContain('run_command');
111 | 		expect(transformedContent).toContain('use_mcp');
112 | 	});
113 | 
114 | 	it('should correctly update file references', () => {
115 | 		const testContent = `---
116 | description: Test Cursor rule for file references
117 | globs: **/*
118 | alwaysApply: true
119 | ---
120 | 
121 | This references [dev_workflow.mdc](mdc:.cursor/rules/dev_workflow.mdc) and 
122 | [taskmaster.mdc](mdc:.cursor/rules/taskmaster.mdc).`;
123 | 
124 | 		// Mock file read to return our test content
125 | 		mockReadFileSync.mockReturnValue(testContent);
126 | 
127 | 		// Call the actual function
128 | 		const result = convertRuleToProfileRule(
129 | 			'source.mdc',
130 | 			'target.md',
131 | 			clineProfile
132 | 		);
133 | 
134 | 		// Verify the function succeeded
135 | 		expect(result).toBe(true);
136 | 
137 | 		// Get the transformed content that was written
138 | 		const writeCall = mockWriteFileSync.mock.calls[0];
139 | 		const transformedContent = writeCall[1];
140 | 
141 | 		// Verify file path transformations - no taskmaster subdirectory for Cline
142 | 		expect(transformedContent).toContain('(.clinerules/dev_workflow.md)');
143 | 		expect(transformedContent).toContain('(.clinerules/taskmaster.md)');
144 | 		expect(transformedContent).not.toContain('(mdc:.cursor/rules/');
145 | 	});
146 | 
147 | 	it('should handle file read errors', () => {
148 | 		// Mock file read to throw an error
149 | 		mockReadFileSync.mockImplementation(() => {
150 | 			throw new Error('File not found');
151 | 		});
152 | 
153 | 		// Call the actual function
154 | 		const result = convertRuleToProfileRule(
155 | 			'nonexistent.mdc',
156 | 			'target.md',
157 | 			clineProfile
158 | 		);
159 | 
160 | 		// Verify the function failed gracefully
161 | 		expect(result).toBe(false);
162 | 
163 | 		// Verify writeFileSync was not called
164 | 		expect(mockWriteFileSync).not.toHaveBeenCalled();
165 | 
166 | 		// Verify error was logged
167 | 		expect(mockConsoleError).toHaveBeenCalledWith(
168 | 			'Error converting rule file: File not found'
169 | 		);
170 | 	});
171 | 
172 | 	it('should handle file write errors', () => {
173 | 		const testContent = 'test content';
174 | 		mockReadFileSync.mockReturnValue(testContent);
175 | 
176 | 		// Mock file write to throw an error
177 | 		mockWriteFileSync.mockImplementation(() => {
178 | 			throw new Error('Permission denied');
179 | 		});
180 | 
181 | 		// Call the actual function
182 | 		const result = convertRuleToProfileRule(
183 | 			'source.mdc',
184 | 			'target.md',
185 | 			clineProfile
186 | 		);
187 | 
188 | 		// Verify the function failed gracefully
189 | 		expect(result).toBe(false);
190 | 
191 | 		// Verify error was logged
192 | 		expect(mockConsoleError).toHaveBeenCalledWith(
193 | 			'Error converting rule file: Permission denied'
194 | 		);
195 | 	});
196 | 
197 | 	it('should create target directory if it does not exist', () => {
198 | 		const testContent = 'test content';
199 | 		mockReadFileSync.mockReturnValue(testContent);
200 | 
201 | 		// Mock directory doesn't exist initially
202 | 		mockExistsSync.mockReturnValue(false);
203 | 
204 | 		// Call the actual function
205 | 		convertRuleToProfileRule(
206 | 			'source.mdc',
207 | 			'some/deep/path/target.md',
208 | 			clineProfile
209 | 		);
210 | 
211 | 		// Verify directory creation was called
212 | 		expect(mockMkdirSync).toHaveBeenCalledWith('some/deep/path', {
213 | 			recursive: true
214 | 		});
215 | 	});
216 | });
217 | 
```

--------------------------------------------------------------------------------
/tests/unit/profiles/rule-transformer-cursor.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { jest } from '@jest/globals';
  2 | 
  3 | // Mock fs module before importing anything that uses it
  4 | jest.mock('fs', () => ({
  5 | 	readFileSync: jest.fn(),
  6 | 	writeFileSync: jest.fn(),
  7 | 	existsSync: jest.fn(),
  8 | 	mkdirSync: jest.fn()
  9 | }));
 10 | 
 11 | // Import modules after mocking
 12 | import fs from 'fs';
 13 | import { convertRuleToProfileRule } from '../../../src/utils/rule-transformer.js';
 14 | import { cursorProfile } from '../../../src/profiles/cursor.js';
 15 | 
 16 | describe('Cursor Rule Transformer', () => {
 17 | 	// Set up spies on the mocked modules
 18 | 	const mockReadFileSync = jest.spyOn(fs, 'readFileSync');
 19 | 	const mockWriteFileSync = jest.spyOn(fs, 'writeFileSync');
 20 | 	const mockExistsSync = jest.spyOn(fs, 'existsSync');
 21 | 	const mockMkdirSync = jest.spyOn(fs, 'mkdirSync');
 22 | 	const mockConsoleError = jest
 23 | 		.spyOn(console, 'error')
 24 | 		.mockImplementation(() => {});
 25 | 
 26 | 	beforeEach(() => {
 27 | 		jest.clearAllMocks();
 28 | 		// Setup default mocks
 29 | 		mockReadFileSync.mockReturnValue('');
 30 | 		mockWriteFileSync.mockImplementation(() => {});
 31 | 		mockExistsSync.mockReturnValue(true);
 32 | 		mockMkdirSync.mockImplementation(() => {});
 33 | 	});
 34 | 
 35 | 	afterAll(() => {
 36 | 		jest.restoreAllMocks();
 37 | 	});
 38 | 
 39 | 	it('should correctly convert basic terms', () => {
 40 | 		const testContent = `---
 41 | description: Test Cursor rule for basic terms
 42 | globs: **/*
 43 | alwaysApply: true
 44 | ---
 45 | 
 46 | This is a Cursor rule that references cursor.so and uses the word Cursor multiple times.
 47 | Also has references to .mdc files.`;
 48 | 
 49 | 		// Mock file read to return our test content
 50 | 		mockReadFileSync.mockReturnValue(testContent);
 51 | 
 52 | 		// Call the actual function
 53 | 		const result = convertRuleToProfileRule(
 54 | 			'source.mdc',
 55 | 			'target.mdc',
 56 | 			cursorProfile
 57 | 		);
 58 | 
 59 | 		// Verify the function succeeded
 60 | 		expect(result).toBe(true);
 61 | 
 62 | 		// Verify file operations were called correctly
 63 | 		expect(mockReadFileSync).toHaveBeenCalledWith('source.mdc', 'utf8');
 64 | 		expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
 65 | 
 66 | 		// Get the transformed content that was written
 67 | 		const writeCall = mockWriteFileSync.mock.calls[0];
 68 | 		const transformedContent = writeCall[1];
 69 | 
 70 | 		// Verify transformations (Cursor profile should keep everything the same)
 71 | 		expect(transformedContent).toContain('Cursor');
 72 | 		expect(transformedContent).toContain('cursor.so');
 73 | 		expect(transformedContent).toContain('.mdc');
 74 | 		expect(transformedContent).toContain('Cursor rule');
 75 | 	});
 76 | 
 77 | 	it('should correctly convert tool references', () => {
 78 | 		const testContent = `---
 79 | description: Test Cursor rule for tool references
 80 | globs: **/*
 81 | alwaysApply: true
 82 | ---
 83 | 
 84 | - Use the search tool to find code
 85 | - The edit_file tool lets you modify files
 86 | - run_command executes terminal commands
 87 | - use_mcp connects to external services`;
 88 | 
 89 | 		// Mock file read to return our test content
 90 | 		mockReadFileSync.mockReturnValue(testContent);
 91 | 
 92 | 		// Call the actual function
 93 | 		const result = convertRuleToProfileRule(
 94 | 			'source.mdc',
 95 | 			'target.mdc',
 96 | 			cursorProfile
 97 | 		);
 98 | 
 99 | 		// Verify the function succeeded
100 | 		expect(result).toBe(true);
101 | 
102 | 		// Get the transformed content that was written
103 | 		const writeCall = mockWriteFileSync.mock.calls[0];
104 | 		const transformedContent = writeCall[1];
105 | 
106 | 		// Verify transformations (Cursor uses standard tool names, so no transformation)
107 | 		expect(transformedContent).toContain('search tool');
108 | 		expect(transformedContent).toContain('edit_file tool');
109 | 		expect(transformedContent).toContain('run_command');
110 | 		expect(transformedContent).toContain('use_mcp');
111 | 	});
112 | 
113 | 	it('should correctly update file references', () => {
114 | 		const testContent = `---
115 | description: Test Cursor rule for file references
116 | globs: **/*
117 | alwaysApply: true
118 | ---
119 | 
120 | This references [dev_workflow.mdc](mdc:.cursor/rules/dev_workflow.mdc) and 
121 | [taskmaster.mdc](mdc:.cursor/rules/taskmaster.mdc).`;
122 | 
123 | 		// Mock file read to return our test content
124 | 		mockReadFileSync.mockReturnValue(testContent);
125 | 
126 | 		// Call the actual function
127 | 		const result = convertRuleToProfileRule(
128 | 			'source.mdc',
129 | 			'target.mdc',
130 | 			cursorProfile
131 | 		);
132 | 
133 | 		// Verify the function succeeded
134 | 		expect(result).toBe(true);
135 | 
136 | 		// Get the transformed content that was written
137 | 		const writeCall = mockWriteFileSync.mock.calls[0];
138 | 		const transformedContent = writeCall[1];
139 | 
140 | 		// Verify transformations (Cursor should keep the same references but in taskmaster subdirectory)
141 | 		expect(transformedContent).toContain(
142 | 			'(mdc:.cursor/rules/taskmaster/dev_workflow.mdc)'
143 | 		);
144 | 		expect(transformedContent).toContain(
145 | 			'(mdc:.cursor/rules/taskmaster/taskmaster.mdc)'
146 | 		);
147 | 	});
148 | 
149 | 	it('should handle file read errors', () => {
150 | 		// Mock file read to throw an error
151 | 		mockReadFileSync.mockImplementation(() => {
152 | 			throw new Error('File not found');
153 | 		});
154 | 
155 | 		// Call the actual function
156 | 		const result = convertRuleToProfileRule(
157 | 			'nonexistent.mdc',
158 | 			'target.mdc',
159 | 			cursorProfile
160 | 		);
161 | 
162 | 		// Verify the function failed gracefully
163 | 		expect(result).toBe(false);
164 | 
165 | 		// Verify writeFileSync was not called
166 | 		expect(mockWriteFileSync).not.toHaveBeenCalled();
167 | 
168 | 		// Verify error was logged
169 | 		expect(mockConsoleError).toHaveBeenCalledWith(
170 | 			'Error converting rule file: File not found'
171 | 		);
172 | 	});
173 | 
174 | 	it('should handle file write errors', () => {
175 | 		const testContent = 'test content';
176 | 		mockReadFileSync.mockReturnValue(testContent);
177 | 
178 | 		// Mock file write to throw an error
179 | 		mockWriteFileSync.mockImplementation(() => {
180 | 			throw new Error('Permission denied');
181 | 		});
182 | 
183 | 		// Call the actual function
184 | 		const result = convertRuleToProfileRule(
185 | 			'source.mdc',
186 | 			'target.mdc',
187 | 			cursorProfile
188 | 		);
189 | 
190 | 		// Verify the function failed gracefully
191 | 		expect(result).toBe(false);
192 | 
193 | 		// Verify error was logged
194 | 		expect(mockConsoleError).toHaveBeenCalledWith(
195 | 			'Error converting rule file: Permission denied'
196 | 		);
197 | 	});
198 | 
199 | 	it('should create target directory if it does not exist', () => {
200 | 		const testContent = 'test content';
201 | 		mockReadFileSync.mockReturnValue(testContent);
202 | 
203 | 		// Mock directory doesn't exist initially
204 | 		mockExistsSync.mockReturnValue(false);
205 | 
206 | 		// Call the actual function
207 | 		convertRuleToProfileRule(
208 | 			'source.mdc',
209 | 			'some/deep/path/target.mdc',
210 | 			cursorProfile
211 | 		);
212 | 
213 | 		// Verify directory creation was called
214 | 		expect(mockMkdirSync).toHaveBeenCalledWith('some/deep/path', {
215 | 			recursive: true
216 | 		});
217 | 	});
218 | });
219 | 
```

--------------------------------------------------------------------------------
/.taskmaster/reports/tm-core-complexity.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 | 	"meta": {
 3 | 		"generatedAt": "2025-08-06T12:15:01.327Z",
 4 | 		"tasksAnalyzed": 8,
 5 | 		"totalTasks": 11,
 6 | 		"analysisCount": 8,
 7 | 		"thresholdScore": 5,
 8 | 		"projectName": "Taskmaster",
 9 | 		"usedResearch": false
10 | 	},
11 | 	"complexityAnalysis": [
12 | 		{
13 | 			"taskId": 118,
14 | 			"taskTitle": "Create AI Provider Base Architecture",
15 | 			"complexityScore": 4,
16 | 			"recommendedSubtasks": 5,
17 | 			"expansionPrompt": "Break down the conversion of base-provider.js to TypeScript BaseProvider class: 1) Convert to TypeScript and define IAIProvider interface, 2) Implement abstract class with core properties, 3) Define abstract methods and Template Method pattern, 4) Add retry logic with exponential backoff, 5) Implement validation and logging. Focus on maintaining compatibility with existing provider pattern while adding type safety.",
18 | 			"reasoning": "The codebase already has a well-established BaseAIProvider class in JavaScript. Converting to TypeScript mainly involves adding type definitions and ensuring the existing pattern is preserved. The complexity is moderate because the pattern is already proven in the codebase."
19 | 		},
20 | 		{
21 | 			"taskId": 119,
22 | 			"taskTitle": "Implement Provider Factory with Dynamic Imports",
23 | 			"complexityScore": 3,
24 | 			"recommendedSubtasks": 5,
25 | 			"expansionPrompt": "Create ProviderFactory implementation: 1) Set up class structure and types, 2) Implement provider selection switch statement, 3) Add dynamic imports for tree-shaking, 4) Handle provider instantiation with config, 5) Add comprehensive error handling. The existing PROVIDERS registry pattern should guide the implementation.",
26 | 			"reasoning": "The codebase already uses a dual registry pattern (static PROVIDERS and dynamic ProviderRegistry). Creating a factory is straightforward as the provider registration patterns are well-established. Dynamic imports are already used in the codebase."
27 | 		},
28 | 		{
29 | 			"taskId": 120,
30 | 			"taskTitle": "Implement Anthropic Provider",
31 | 			"complexityScore": 3,
32 | 			"recommendedSubtasks": 5,
33 | 			"expansionPrompt": "Implement AnthropicProvider following existing patterns: 1) Create class structure with imports, 2) Implement constructor and client initialization, 3) Add generateCompletion with Claude API integration, 4) Implement token calculation and utility methods, 5) Add error handling and exports. Use the existing anthropic.js provider as reference.",
34 | 			"reasoning": "AnthropicProvider already exists in the codebase with full implementation. This task essentially involves adapting the existing implementation to match the new TypeScript architecture, making it relatively straightforward."
35 | 		},
36 | 		{
37 | 			"taskId": 121,
38 | 			"taskTitle": "Create Prompt Builder and Task Parser",
39 | 			"complexityScore": 6,
40 | 			"recommendedSubtasks": 5,
41 | 			"expansionPrompt": "Build prompt system and parser: 1) Create PromptBuilder with template methods, 2) Implement TaskParser with dependency injection, 3) Add parsePRD core logic with file reading, 4) Implement task enrichment and metadata, 5) Add comprehensive error handling. Leverage the existing prompt management system in src/prompts/.",
42 | 			"reasoning": "While the codebase has a sophisticated prompt management system, creating a new PromptBuilder and TaskParser requires understanding the existing prompt templates, JSON schema validation, and integration with the AI provider system. The task involves significant new code."
43 | 		},
44 | 		{
45 | 			"taskId": 122,
46 | 			"taskTitle": "Implement Configuration Management",
47 | 			"complexityScore": 5,
48 | 			"recommendedSubtasks": 5,
49 | 			"expansionPrompt": "Create ConfigManager with validation: 1) Define Zod schema for IConfiguration, 2) Implement constructor with defaults, 3) Add validate method with error handling, 4) Create type-safe get method with generics, 5) Implement getAll and finalize exports. Reference existing config-manager.js for patterns.",
50 | 			"reasoning": "The codebase has an existing config-manager.js with sophisticated configuration handling. Adding Zod validation and TypeScript generics adds complexity, but the existing patterns provide a solid foundation."
51 | 		},
52 | 		{
53 | 			"taskId": 123,
54 | 			"taskTitle": "Create Utility Functions and Error Handling",
55 | 			"complexityScore": 2,
56 | 			"recommendedSubtasks": 5,
57 | 			"expansionPrompt": "Implement utilities and error handling: 1) Create ID generation module with unique formats, 2) Build TaskMasterError base class, 3) Add error sanitization for security, 4) Implement development-only logging, 5) Create specialized error subclasses. Keep implementation simple and focused.",
58 | 			"reasoning": "This is a straightforward utility implementation task. The codebase already has error handling patterns, and ID generation is a simple algorithmic task. The main work is creating clean, reusable utilities."
59 | 		},
60 | 		{
61 | 			"taskId": 124,
62 | 			"taskTitle": "Implement TaskMasterCore Facade",
63 | 			"complexityScore": 7,
64 | 			"recommendedSubtasks": 5,
65 | 			"expansionPrompt": "Create main facade class: 1) Set up TaskMasterCore structure with imports, 2) Implement lazy initialization logic, 3) Add parsePRD coordination method, 4) Implement getTasks and other facade methods, 5) Create factory function and exports. This ties together all other components into a cohesive API.",
66 | 			"reasoning": "This is the most complex task as it requires understanding and integrating all other components. The facade must coordinate between configuration, providers, storage, and parsing while maintaining a clean API. It's the architectural keystone of the system."
67 | 		},
68 | 		{
69 | 			"taskId": 125,
70 | 			"taskTitle": "Create Placeholder Providers and Complete Testing",
71 | 			"complexityScore": 5,
72 | 			"recommendedSubtasks": 5,
73 | 			"expansionPrompt": "Implement testing infrastructure: 1) Create OpenAIProvider placeholder, 2) Create GoogleProvider placeholder, 3) Build MockProvider for testing, 4) Write TaskParser unit tests, 5) Create integration tests for parse-prd flow. Follow the existing test patterns in tests/ directory.",
74 | 			"reasoning": "While creating placeholder providers is simple, the testing infrastructure requires understanding Jest with ES modules, mocking patterns, and comprehensive test coverage. The existing test structure provides good examples to follow."
75 | 		}
76 | 	]
77 | }
78 | 
```

--------------------------------------------------------------------------------
/apps/extension/src/components/TaskDetailsView.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import type React from 'react';
  2 | import { useContext, useState, useCallback } from 'react';
  3 | import { Button } from '@/components/ui/button';
  4 | import { useQueryClient } from '@tanstack/react-query';
  5 | import { RefreshCw } from 'lucide-react';
  6 | import {
  7 | 	Breadcrumb,
  8 | 	BreadcrumbItem,
  9 | 	BreadcrumbLink,
 10 | 	BreadcrumbList,
 11 | 	BreadcrumbSeparator
 12 | } from '@/components/ui/breadcrumb';
 13 | import { VSCodeContext } from '../webview/contexts/VSCodeContext';
 14 | import { AIActionsSection } from './TaskDetails/AIActionsSection';
 15 | import { SubtasksSection } from './TaskDetails/SubtasksSection';
 16 | import { TaskMetadataSidebar } from './TaskDetails/TaskMetadataSidebar';
 17 | import { DetailsSection } from './TaskDetails/DetailsSection';
 18 | import { useTaskDetails } from './TaskDetails/useTaskDetails';
 19 | import { useTasks, taskKeys } from '../webview/hooks/useTaskQueries';
 20 | import type { TaskMasterTask } from '../webview/types';
 21 | 
 22 | interface TaskDetailsViewProps {
 23 | 	taskId: string;
 24 | 	onNavigateBack: () => void;
 25 | 	onNavigateToTask: (taskId: string) => void;
 26 | }
 27 | 
 28 | export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
 29 | 	taskId,
 30 | 	onNavigateBack,
 31 | 	onNavigateToTask
 32 | }) => {
 33 | 	const context = useContext(VSCodeContext);
 34 | 	if (!context) {
 35 | 		throw new Error('TaskDetailsView must be used within VSCodeProvider');
 36 | 	}
 37 | 
 38 | 	const { state, sendMessage } = context;
 39 | 	const { currentTag } = state;
 40 | 	const queryClient = useQueryClient();
 41 | 	const [isRefreshing, setIsRefreshing] = useState(false);
 42 | 
 43 | 	// Use React Query to fetch all tasks
 44 | 	const { data: allTasks = [] } = useTasks({ tag: currentTag });
 45 | 
 46 | 	const {
 47 | 		currentTask,
 48 | 		parentTask,
 49 | 		isSubtask,
 50 | 		taskFileData,
 51 | 		taskFileDataError,
 52 | 		complexity,
 53 | 		refreshComplexityAfterAI
 54 | 	} = useTaskDetails({ taskId, sendMessage, tasks: allTasks });
 55 | 
 56 | 	const displayId =
 57 | 		isSubtask && parentTask
 58 | 			? `${parentTask.id}.${currentTask?.id}`
 59 | 			: currentTask?.id;
 60 | 
 61 | 	const handleStatusChange = async (newStatus: TaskMasterTask['status']) => {
 62 | 		if (!currentTask) return;
 63 | 
 64 | 		try {
 65 | 			await sendMessage({
 66 | 				type: 'updateTaskStatus',
 67 | 				data: {
 68 | 					taskId: displayId,
 69 | 					newStatus: newStatus
 70 | 				}
 71 | 			});
 72 | 		} catch (error) {
 73 | 			console.error('❌ TaskDetailsView: Failed to update task status:', error);
 74 | 		}
 75 | 	};
 76 | 
 77 | 	const handleDependencyClick = (depId: string) => {
 78 | 		onNavigateToTask(depId);
 79 | 	};
 80 | 
 81 | 	const handleRefresh = useCallback(async () => {
 82 | 		setIsRefreshing(true);
 83 | 		try {
 84 | 			// Invalidate all task queries
 85 | 			await queryClient.invalidateQueries({ queryKey: taskKeys.all });
 86 | 		} finally {
 87 | 			// Reset after a short delay to show the animation
 88 | 			setTimeout(() => setIsRefreshing(false), 500);
 89 | 		}
 90 | 	}, [queryClient]);
 91 | 
 92 | 	if (!currentTask) {
 93 | 		return (
 94 | 			<div className="flex items-center justify-center h-full">
 95 | 				<div className="text-center">
 96 | 					<p className="text-lg text-vscode-foreground/70 mb-4">
 97 | 						Task not found
 98 | 					</p>
 99 | 					<Button onClick={onNavigateBack} variant="outline">
100 | 						Back to Kanban Board
101 | 					</Button>
102 | 				</div>
103 | 			</div>
104 | 		);
105 | 	}
106 | 
107 | 	return (
108 | 		<div className="h-full flex flex-col">
109 | 			<div className="flex-1 grid grid-cols-1 md:grid-cols-3 gap-6 p-6 overflow-auto">
110 | 				{/* Left column - Main content (2/3 width) */}
111 | 				<div className="md:col-span-2 space-y-6">
112 | 					{/* Breadcrumb navigation */}
113 | 					<div className="flex items-center justify-between">
114 | 						<Breadcrumb>
115 | 							<BreadcrumbList>
116 | 								<BreadcrumbItem>
117 | 									<BreadcrumbLink
118 | 										onClick={onNavigateBack}
119 | 										className="cursor-pointer hover:text-vscode-foreground text-link"
120 | 									>
121 | 										Kanban Board
122 | 									</BreadcrumbLink>
123 | 								</BreadcrumbItem>
124 | 								{isSubtask && parentTask && (
125 | 									<>
126 | 										<BreadcrumbSeparator />
127 | 										<BreadcrumbItem>
128 | 											<BreadcrumbLink
129 | 												onClick={() => onNavigateToTask(parentTask.id)}
130 | 												className="cursor-pointer hover:text-vscode-foreground"
131 | 											>
132 | 												{parentTask.title}
133 | 											</BreadcrumbLink>
134 | 										</BreadcrumbItem>
135 | 									</>
136 | 								)}
137 | 								<BreadcrumbSeparator />
138 | 								<BreadcrumbItem>
139 | 									<span className="text-vscode-foreground">
140 | 										#{displayId} {currentTask.title}
141 | 									</span>
142 | 								</BreadcrumbItem>
143 | 							</BreadcrumbList>
144 | 						</Breadcrumb>
145 | 						<button
146 | 							onClick={handleRefresh}
147 | 							disabled={isRefreshing}
148 | 							className="p-1.5 rounded hover:bg-vscode-button-hoverBackground transition-colors"
149 | 							title="Refresh task details"
150 | 						>
151 | 							<RefreshCw
152 | 								className={`w-4 h-4 text-vscode-foreground/70 ${isRefreshing ? 'animate-spin' : ''}`}
153 | 							/>
154 | 						</button>
155 | 					</div>
156 | 
157 | 					{/* Task ID and title */}
158 | 					<h1 className="text-2xl font-bold tracking-tight text-vscode-foreground">
159 | 						#{displayId} {currentTask.title}
160 | 					</h1>
161 | 
162 | 					{/* Description */}
163 | 					<div className="mb-8">
164 | 						<p className="text-vscode-foreground/80 leading-relaxed">
165 | 							{currentTask.description || 'No description available.'}
166 | 						</p>
167 | 					</div>
168 | 
169 | 					{/* AI Actions */}
170 | 					<AIActionsSection
171 | 						currentTask={currentTask}
172 | 						isSubtask={isSubtask}
173 | 						parentTask={parentTask}
174 | 						sendMessage={sendMessage}
175 | 						refreshComplexityAfterAI={refreshComplexityAfterAI}
176 | 					/>
177 | 
178 | 					{/* Implementation Details */}
179 | 					<DetailsSection
180 | 						title="Implementation Details"
181 | 						content={taskFileData.details}
182 | 						error={taskFileDataError}
183 | 						emptyMessage="No implementation details available"
184 | 						defaultExpanded={false}
185 | 					/>
186 | 
187 | 					{/* Test Strategy */}
188 | 					<DetailsSection
189 | 						title="Test Strategy"
190 | 						content={taskFileData.testStrategy}
191 | 						error={taskFileDataError}
192 | 						emptyMessage="No test strategy available"
193 | 						defaultExpanded={false}
194 | 					/>
195 | 
196 | 					{/* Subtasks */}
197 | 					<SubtasksSection
198 | 						currentTask={currentTask}
199 | 						isSubtask={isSubtask}
200 | 						sendMessage={sendMessage}
201 | 						onNavigateToTask={onNavigateToTask}
202 | 					/>
203 | 				</div>
204 | 
205 | 				{/* Right column - Metadata (1/3 width) */}
206 | 				<TaskMetadataSidebar
207 | 					currentTask={currentTask}
208 | 					tasks={allTasks}
209 | 					complexity={complexity}
210 | 					isSubtask={isSubtask}
211 | 					onStatusChange={handleStatusChange}
212 | 					onDependencyClick={handleDependencyClick}
213 | 				/>
214 | 			</div>
215 | 		</div>
216 | 	);
217 | };
218 | 
219 | export default TaskDetailsView;
220 | 
```

--------------------------------------------------------------------------------
/docs/claude-code-integration.md:
--------------------------------------------------------------------------------

```markdown
  1 | # TODO: Move to apps/docs inside our documentation website
  2 | 
  3 | # Claude Code Integration Guide
  4 | 
  5 | This guide covers how to use Task Master with Claude Code AI SDK integration for enhanced AI-powered development workflows.
  6 | 
  7 | ## Overview
  8 | 
  9 | Claude Code integration allows Task Master to leverage the Claude Code CLI for AI operations without requiring direct API keys. The integration uses OAuth tokens managed by the Claude Code CLI itself.
 10 | 
 11 | ## Authentication Setup
 12 | 
 13 | The Claude Code provider uses token authentication managed by the Claude Code CLI.
 14 | 
 15 | ### Prerequisites
 16 | 
 17 | 1. **Install Claude Code CLI** (if not already installed):
 18 | 
 19 |    ```bash
 20 |    # Installation method depends on your system
 21 |    # Follow Claude Code documentation for installation
 22 |    ```
 23 | 
 24 | 2. **Set up OAuth token** using Claude Code CLI:
 25 | 
 26 |    ```bash
 27 |    claude setup-token
 28 |    ```
 29 | 
 30 |    This command will:
 31 |    - Guide you through OAuth authentication
 32 |    - Store the token securely for CLI usage
 33 |    - Enable Task Master to use Claude Code without manual API key configuration
 34 | 
 35 | ### Authentication Priority
 36 | 
 37 | Task Master will attempt authentication in this order:
 38 | 
 39 | 1. **Environment Variable** (optional): `CLAUDE_CODE_OAUTH_TOKEN`
 40 |    - Useful for CI/CD environments or when you want to override the default token
 41 |    - Not required if you've set up the CLI token
 42 | 
 43 | 2. **Claude Code CLI Token** (recommended): Token managed by `claude setup-token`
 44 |    - Automatically used when available
 45 |    - Most convenient for local development
 46 | 
 47 | 3. **Fallback**: Error if neither is available
 48 | 
 49 | ## Configuration
 50 | 
 51 | ### Basic Configuration
 52 | 
 53 | Add Claude Code to your Task Master configuration:
 54 | 
 55 | ```javascript
 56 | // In your .taskmaster/config.json or via task-master models command
 57 | {
 58 |   "models": {
 59 |     "main": "claude-code:sonnet",      // Use Claude Code with Sonnet
 60 |     "research": "perplexity-llama-3.1-sonar-large-128k-online",
 61 |     "fallback": "claude-code:opus"     // Use Claude Code with Opus as fallback
 62 |   }
 63 | }
 64 | ```
 65 | 
 66 | ### Supported Models
 67 | 
 68 | - `claude-code:sonnet` - Claude 3.5 Sonnet via Claude Code CLI
 69 | - `claude-code:opus` - Claude 3 Opus via Claude Code CLI
 70 | 
 71 | ### Environment Variables (Optional)
 72 | 
 73 | While not required, you can optionally set:
 74 | 
 75 | ```bash
 76 | export CLAUDE_CODE_OAUTH_TOKEN="your_oauth_token_here"
 77 | ```
 78 | 
 79 | This is only needed in specific scenarios like:
 80 | 
 81 | - CI/CD pipelines
 82 | - Docker containers
 83 | - When you want to use a different token than the CLI default
 84 | 
 85 | ## Usage Examples
 86 | 
 87 | ### Basic Task Operations
 88 | 
 89 | ```bash
 90 | # Use Claude Code for task operations
 91 | task-master add-task --prompt="Implement user authentication system" --research
 92 | task-master expand --id=1 --research
 93 | task-master update-task --id=1.1 --prompt="Add JWT token validation"
 94 | ```
 95 | 
 96 | ### Model Configuration Commands
 97 | 
 98 | ```bash
 99 | # Set Claude Code as main model
100 | task-master models --set-main claude-code:sonnet
101 | 
102 | # Use interactive setup
103 | task-master models --setup
104 | # Then select "claude-code" from the provider list
105 | ```
106 | 
107 | ## Troubleshooting
108 | 
109 | ### Common Issues
110 | 
111 | #### 1. "Claude Code CLI not available" Error
112 | 
113 | **Problem**: Task Master cannot connect to Claude Code CLI.
114 | 
115 | **Solutions**:
116 | 
117 | - Ensure Claude Code CLI is installed and in your PATH
118 | - Run `claude setup-token` to configure authentication
119 | - Verify Claude Code CLI works: `claude --help`
120 | 
121 | #### 2. Authentication Failures
122 | 
123 | **Problem**: Token authentication is failing.
124 | 
125 | **Solutions**:
126 | 
127 | - Re-run `claude setup-token` to refresh your OAuth token
128 | - Check if your token has expired
129 | - Verify Claude Code CLI can authenticate: try a simple `claude` command
130 | 
131 | #### 3. Model Not Available
132 | 
133 | **Problem**: Specified Claude Code model is not supported.
134 | 
135 | **Solutions**:
136 | 
137 | - Use supported models: `sonnet` or `opus`
138 | - Check model availability: `task-master models --list`
139 | - Verify your Claude Code CLI has access to the requested model
140 | 
141 | ### Debug Steps
142 | 
143 | 1. **Test Claude Code CLI directly**:
144 | 
145 |    ```bash
146 |    claude --help
147 |    # Should show help without errors
148 |    ```
149 | 
150 | 2. **Test authentication**:
151 | 
152 |    ```bash
153 |    claude setup-token --verify
154 |    # Should confirm token is valid
155 |    ```
156 | 
157 | 3. **Test Task Master integration**:
158 | 
159 |    ```bash
160 |    task-master models --test claude-code:sonnet
161 |    # Should successfully connect and test the model
162 |    ```
163 | 
164 | 4. **Check logs**:
165 |    - Task Master logs will show detailed error messages
166 |    - Use `--verbose` flag for more detailed output
167 | 
168 | ### Environment-Specific Configuration
169 | 
170 | #### Docker/Containers
171 | 
172 | When running in Docker, you'll need to:
173 | 
174 | 1. Install Claude Code CLI in your container
175 | 2. Set up authentication via environment variable:
176 | 
177 |    ```dockerfile
178 |    ENV CLAUDE_CODE_OAUTH_TOKEN="your_token_here"
179 |    ```
180 | 
181 | #### CI/CD Pipelines
182 | 
183 | For automated environments:
184 | 
185 | 1. Set up a service account token or use environment variables
186 | 2. Ensure Claude Code CLI is available in the pipeline environment
187 | 3. Configure authentication before running Task Master commands
188 | 
189 | ## Integration with AI SDK
190 | 
191 | Task Master's Claude Code integration uses the official `ai-sdk-provider-claude-code` package, providing:
192 | 
193 | - **Streaming Support**: Real-time token streaming for interactive experiences
194 | - **Full AI SDK Compatibility**: Works with generateText, streamText, and other AI SDK functions
195 | - **Automatic Error Handling**: Graceful degradation when Claude Code is unavailable
196 | - **Type Safety**: Full TypeScript support with proper type definitions
197 | 
198 | ### Example AI SDK Usage
199 | 
200 | ```javascript
201 | import { generateText } from 'ai';
202 | import { ClaudeCodeProvider } from './src/ai-providers/claude-code.js';
203 | 
204 | const provider = new ClaudeCodeProvider();
205 | const client = provider.getClient();
206 | 
207 | const result = await generateText({
208 |   model: client('sonnet'),
209 |   messages: [
210 |     { role: 'user', content: 'Hello Claude!' }
211 |   ]
212 | });
213 | 
214 | console.log(result.text);
215 | ```
216 | 
217 | ## Security Notes
218 | 
219 | - OAuth tokens are managed securely by Claude Code CLI
220 | - No API keys need to be stored in your project files
221 | - Tokens are automatically refreshed by the Claude Code CLI
222 | - Environment variables should only be used in secure environments
223 | 
224 | ## Getting Help
225 | 
226 | If you encounter issues:
227 | 
228 | 1. Check the Claude Code CLI documentation
229 | 2. Verify your authentication setup with `claude setup-token --verify`
230 | 3. Review Task Master logs for detailed error messages
231 | 4. Open an issue with both Task Master and Claude Code version information
232 | 
```

--------------------------------------------------------------------------------
/src/profiles/kilo.js:
--------------------------------------------------------------------------------

```javascript
  1 | // Kilo Code conversion profile for rule-transformer
  2 | import path from 'path';
  3 | import fs from 'fs';
  4 | import { isSilentMode, log } from '../../scripts/modules/utils.js';
  5 | import { createProfile, COMMON_TOOL_MAPPINGS } from './base-profile.js';
  6 | import { ROO_MODES } from '../constants/profiles.js';
  7 | 
  8 | // Utility function to apply kilo transformations to content
  9 | function applyKiloTransformations(content) {
 10 | 	const customReplacements = [
 11 | 		// Replace roo-specific terms with kilo equivalents
 12 | 		{
 13 | 			from: /\broo\b/gi,
 14 | 			to: (match) => (match.charAt(0) === 'R' ? 'Kilo' : 'kilo')
 15 | 		},
 16 | 		{ from: /Roo/g, to: 'Kilo' },
 17 | 		{ from: /ROO/g, to: 'KILO' },
 18 | 		{ from: /roocode\.com/gi, to: 'kilocode.com' },
 19 | 		{ from: /docs\.roocode\.com/gi, to: 'docs.kilocode.com' },
 20 | 		{ from: /https?:\/\/roocode\.com/gi, to: 'https://kilocode.com' },
 21 | 		{
 22 | 			from: /https?:\/\/docs\.roocode\.com/gi,
 23 | 			to: 'https://docs.kilocode.com'
 24 | 		},
 25 | 		{ from: /\.roo\//g, to: '.kilo/' },
 26 | 		{ from: /\.roomodes/g, to: '.kilocodemodes' },
 27 | 		// Handle file extensions and directory references
 28 | 		{ from: /roo-rules/g, to: 'kilo-rules' },
 29 | 		{ from: /rules-roo/g, to: 'rules-kilo' }
 30 | 	];
 31 | 
 32 | 	let transformedContent = content;
 33 | 	for (const replacement of customReplacements) {
 34 | 		transformedContent = transformedContent.replace(
 35 | 			replacement.from,
 36 | 			replacement.to
 37 | 		);
 38 | 	}
 39 | 	return transformedContent;
 40 | }
 41 | 
 42 | // Utility function to copy files recursively
 43 | function copyRecursiveSync(src, dest) {
 44 | 	const exists = fs.existsSync(src);
 45 | 	const stats = exists && fs.statSync(src);
 46 | 	const isDirectory = exists && stats.isDirectory();
 47 | 	if (isDirectory) {
 48 | 		if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
 49 | 		fs.readdirSync(src).forEach((childItemName) => {
 50 | 			copyRecursiveSync(
 51 | 				path.join(src, childItemName),
 52 | 				path.join(dest, childItemName)
 53 | 			);
 54 | 		});
 55 | 	} else {
 56 | 		fs.copyFileSync(src, dest);
 57 | 	}
 58 | }
 59 | 
 60 | // Lifecycle functions for Kilo profile
 61 | function onAddRulesProfile(targetDir, assetsDir) {
 62 | 	// Use the provided assets directory to find the roocode directory
 63 | 	const sourceDir = path.join(assetsDir, 'roocode');
 64 | 
 65 | 	if (!fs.existsSync(sourceDir)) {
 66 | 		log('error', `[Kilo] Source directory does not exist: ${sourceDir}`);
 67 | 		return;
 68 | 	}
 69 | 
 70 | 	// Copy basic roocode structure first
 71 | 	copyRecursiveSync(sourceDir, targetDir);
 72 | 	log('debug', `[Kilo] Copied roocode directory to ${targetDir}`);
 73 | 
 74 | 	// Transform .roomodes to .kilocodemodes
 75 | 	const roomodesSrc = path.join(sourceDir, '.roomodes');
 76 | 	const kilocodemodesDest = path.join(targetDir, '.kilocodemodes');
 77 | 	if (fs.existsSync(roomodesSrc)) {
 78 | 		try {
 79 | 			const roomodesContent = fs.readFileSync(roomodesSrc, 'utf8');
 80 | 			const transformedContent = applyKiloTransformations(roomodesContent);
 81 | 			fs.writeFileSync(kilocodemodesDest, transformedContent);
 82 | 			log('debug', `[Kilo] Created .kilocodemodes at ${kilocodemodesDest}`);
 83 | 
 84 | 			// Remove the original .roomodes file
 85 | 			fs.unlinkSync(path.join(targetDir, '.roomodes'));
 86 | 		} catch (err) {
 87 | 			log('error', `[Kilo] Failed to transform .roomodes: ${err.message}`);
 88 | 		}
 89 | 	}
 90 | 
 91 | 	// Transform .roo directory to .kilo and apply kilo transformations to mode-specific rules
 92 | 	const rooModesDir = path.join(sourceDir, '.roo');
 93 | 	const kiloModesDir = path.join(targetDir, '.kilo');
 94 | 
 95 | 	// Remove the copied .roo directory and create .kilo
 96 | 	if (fs.existsSync(path.join(targetDir, '.roo'))) {
 97 | 		fs.rmSync(path.join(targetDir, '.roo'), { recursive: true, force: true });
 98 | 	}
 99 | 
100 | 	for (const mode of ROO_MODES) {
101 | 		const src = path.join(rooModesDir, `rules-${mode}`, `${mode}-rules`);
102 | 		const dest = path.join(kiloModesDir, `rules-${mode}`, `${mode}-rules`);
103 | 		if (fs.existsSync(src)) {
104 | 			try {
105 | 				const destDir = path.dirname(dest);
106 | 				if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
107 | 
108 | 				// Read, transform, and write the rule file
109 | 				const ruleContent = fs.readFileSync(src, 'utf8');
110 | 				const transformedContent = applyKiloTransformations(ruleContent);
111 | 				fs.writeFileSync(dest, transformedContent);
112 | 
113 | 				log('debug', `[Kilo] Transformed and copied ${mode}-rules to ${dest}`);
114 | 			} catch (err) {
115 | 				log(
116 | 					'error',
117 | 					`[Kilo] Failed to transform ${src} to ${dest}: ${err.message}`
118 | 				);
119 | 			}
120 | 		}
121 | 	}
122 | }
123 | 
124 | function onRemoveRulesProfile(targetDir) {
125 | 	const kilocodemodespath = path.join(targetDir, '.kilocodemodes');
126 | 	if (fs.existsSync(kilocodemodespath)) {
127 | 		try {
128 | 			fs.rmSync(kilocodemodespath, { force: true });
129 | 			log('debug', `[Kilo] Removed .kilocodemodes from ${kilocodemodespath}`);
130 | 		} catch (err) {
131 | 			log('error', `[Kilo] Failed to remove .kilocodemodes: ${err.message}`);
132 | 		}
133 | 	}
134 | 
135 | 	const kiloDir = path.join(targetDir, '.kilo');
136 | 	if (fs.existsSync(kiloDir)) {
137 | 		fs.readdirSync(kiloDir).forEach((entry) => {
138 | 			if (entry.startsWith('rules-')) {
139 | 				const modeDir = path.join(kiloDir, entry);
140 | 				try {
141 | 					fs.rmSync(modeDir, { recursive: true, force: true });
142 | 					log('debug', `[Kilo] Removed ${entry} directory from ${modeDir}`);
143 | 				} catch (err) {
144 | 					log('error', `[Kilo] Failed to remove ${modeDir}: ${err.message}`);
145 | 				}
146 | 			}
147 | 		});
148 | 		if (fs.readdirSync(kiloDir).length === 0) {
149 | 			try {
150 | 				fs.rmSync(kiloDir, { recursive: true, force: true });
151 | 				log('debug', `[Kilo] Removed empty .kilo directory from ${kiloDir}`);
152 | 			} catch (err) {
153 | 				log('error', `[Kilo] Failed to remove .kilo directory: ${err.message}`);
154 | 			}
155 | 		}
156 | 	}
157 | }
158 | 
159 | function onPostConvertRulesProfile(targetDir, assetsDir) {
160 | 	onAddRulesProfile(targetDir, assetsDir);
161 | }
162 | 
163 | // Create and export kilo profile using the base factory with roo rule reuse
164 | export const kiloProfile = createProfile({
165 | 	name: 'kilo',
166 | 	displayName: 'Kilo Code',
167 | 	url: 'kilocode.com',
168 | 	docsUrl: 'docs.kilocode.com',
169 | 	profileDir: '.kilo',
170 | 	rulesDir: '.kilo/rules',
171 | 	toolMappings: COMMON_TOOL_MAPPINGS.ROO_STYLE,
172 | 
173 | 	fileMap: {
174 | 		// Map roo rule files to kilo equivalents
175 | 		'rules/cursor_rules.mdc': 'kilo_rules.md',
176 | 		'rules/dev_workflow.mdc': 'dev_workflow.md',
177 | 		'rules/self_improve.mdc': 'self_improve.md',
178 | 		'rules/taskmaster.mdc': 'taskmaster.md'
179 | 	},
180 | 	onAdd: onAddRulesProfile,
181 | 	onRemove: onRemoveRulesProfile,
182 | 	onPostConvert: onPostConvertRulesProfile
183 | });
184 | 
185 | // Export lifecycle functions separately to avoid naming conflicts
186 | export { onAddRulesProfile, onRemoveRulesProfile, onPostConvertRulesProfile };
187 | 
```

--------------------------------------------------------------------------------
/packages/tm-core/src/common/types/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Core type definitions for Task Master
  3 |  */
  4 | 
  5 | /**
  6 |  * Storage type options
  7 |  * - 'file': Local file system storage
  8 |  * - 'api': Remote API storage (Hamster integration)
  9 |  * - 'auto': Automatically detect based on auth status
 10 |  */
 11 | export type StorageType = 'file' | 'api' | 'auto';
 12 | 
 13 | // ============================================================================
 14 | // Type Literals
 15 | // ============================================================================
 16 | 
 17 | /**
 18 |  * Task status values
 19 |  */
 20 | export type TaskStatus =
 21 | 	| 'pending'
 22 | 	| 'in-progress'
 23 | 	| 'done'
 24 | 	| 'deferred'
 25 | 	| 'cancelled'
 26 | 	| 'blocked'
 27 | 	| 'review'
 28 | 	| 'completed';
 29 | 
 30 | /**
 31 |  * Task priority levels
 32 |  */
 33 | export type TaskPriority = 'low' | 'medium' | 'high' | 'critical';
 34 | 
 35 | /**
 36 |  * Task complexity levels
 37 |  */
 38 | export type TaskComplexity = 'simple' | 'moderate' | 'complex' | 'very-complex';
 39 | 
 40 | // ============================================================================
 41 | // Core Interfaces
 42 | // ============================================================================
 43 | 
 44 | /**
 45 |  * Placeholder task interface for temporary/minimal task objects
 46 |  */
 47 | export interface PlaceholderTask {
 48 | 	id: string;
 49 | 	title: string;
 50 | 	status: TaskStatus;
 51 | 	priority: TaskPriority;
 52 | }
 53 | 
 54 | /**
 55 |  * Base task interface
 56 |  */
 57 | export interface Task {
 58 | 	id: string;
 59 | 	title: string;
 60 | 	description: string;
 61 | 	status: TaskStatus;
 62 | 	priority: TaskPriority;
 63 | 	dependencies: string[];
 64 | 	details: string;
 65 | 	testStrategy: string;
 66 | 	subtasks: Subtask[];
 67 | 
 68 | 	// Optional enhanced properties
 69 | 	createdAt?: string;
 70 | 	updatedAt?: string;
 71 | 	effort?: number;
 72 | 	actualEffort?: number;
 73 | 	tags?: string[];
 74 | 	assignee?: string;
 75 | 
 76 | 	// Database UUID (for API calls that need the actual UUID instead of display_id)
 77 | 	databaseId?: string;
 78 | 
 79 | 	// Complexity analysis (from complexity report)
 80 | 	// Can be either enum ('simple' | 'moderate' | 'complex' | 'very-complex') or numeric score (1-10)
 81 | 	complexity?: TaskComplexity | number;
 82 | 	recommendedSubtasks?: number;
 83 | 	expansionPrompt?: string;
 84 | 	complexityReasoning?: string;
 85 | }
 86 | 
 87 | /**
 88 |  * Subtask interface extending Task
 89 |  * ID can be number (file storage) or string (API storage with display_id)
 90 |  */
 91 | export interface Subtask extends Omit<Task, 'id' | 'subtasks'> {
 92 | 	id: number | string;
 93 | 	parentId: string;
 94 | 	subtasks?: never; // Subtasks cannot have their own subtasks
 95 | }
 96 | 
 97 | /**
 98 |  * Task metadata for tracking overall project state
 99 |  */
100 | export interface TaskMetadata {
101 | 	version: string;
102 | 	lastModified: string;
103 | 	taskCount: number;
104 | 	completedCount: number;
105 | 	projectName?: string;
106 | 	description?: string;
107 | 	tags?: string[];
108 | 	created?: string;
109 | 	updated?: string;
110 | }
111 | 
112 | /**
113 |  * Task collection with metadata
114 |  */
115 | export interface TaskCollection {
116 | 	tasks: Task[];
117 | 	metadata: TaskMetadata;
118 | }
119 | 
120 | /**
121 |  * Task tag for organizing tasks
122 |  */
123 | export interface TaskTag {
124 | 	name: string;
125 | 	tasks: string[]; // Task IDs belonging to this tag
126 | 	metadata: Record<string, any>;
127 | }
128 | 
129 | // ============================================================================
130 | // Utility Types
131 | // ============================================================================
132 | 
133 | /**
134 |  * Type for creating a new task (without generated fields)
135 |  */
136 | export type CreateTask = Omit<
137 | 	Task,
138 | 	'id' | 'createdAt' | 'updatedAt' | 'subtasks'
139 | > & {
140 | 	subtasks?: Omit<Subtask, 'id' | 'parentId' | 'createdAt' | 'updatedAt'>[];
141 | };
142 | 
143 | /**
144 |  * Type for updating a task (all fields optional except ID)
145 |  */
146 | export type UpdateTask = Partial<Omit<Task, 'id'>> & {
147 | 	id: string;
148 | };
149 | 
150 | /**
151 |  * Type for task filters
152 |  */
153 | export interface TaskFilter {
154 | 	status?: TaskStatus | TaskStatus[];
155 | 	priority?: TaskPriority | TaskPriority[];
156 | 	tags?: string[];
157 | 	hasSubtasks?: boolean;
158 | 	search?: string;
159 | 	assignee?: string;
160 | }
161 | 
162 | /**
163 |  * Type for sort options
164 |  */
165 | export interface TaskSortOptions {
166 | 	field: keyof Task;
167 | 	direction: 'asc' | 'desc';
168 | }
169 | 
170 | // ============================================================================
171 | // Type Guards
172 | // ============================================================================
173 | 
174 | /**
175 |  * Type guard to check if a value is a valid TaskStatus
176 |  */
177 | export function isTaskStatus(value: unknown): value is TaskStatus {
178 | 	return (
179 | 		typeof value === 'string' &&
180 | 		[
181 | 			'pending',
182 | 			'in-progress',
183 | 			'done',
184 | 			'deferred',
185 | 			'cancelled',
186 | 			'blocked',
187 | 			'review'
188 | 		].includes(value)
189 | 	);
190 | }
191 | 
192 | /**
193 |  * Type guard to check if a value is a valid TaskPriority
194 |  */
195 | export function isTaskPriority(value: unknown): value is TaskPriority {
196 | 	return (
197 | 		typeof value === 'string' &&
198 | 		['low', 'medium', 'high', 'critical'].includes(value)
199 | 	);
200 | }
201 | 
202 | /**
203 |  * Type guard to check if a value is a valid TaskComplexity
204 |  */
205 | export function isTaskComplexity(value: unknown): value is TaskComplexity {
206 | 	return (
207 | 		typeof value === 'string' &&
208 | 		['simple', 'moderate', 'complex', 'very-complex'].includes(value)
209 | 	);
210 | }
211 | 
212 | /**
213 |  * Type guard to check if an object is a Task
214 |  */
215 | export function isTask(obj: unknown): obj is Task {
216 | 	if (!obj || typeof obj !== 'object') return false;
217 | 	const task = obj as Record<string, unknown>;
218 | 
219 | 	return (
220 | 		typeof task.id === 'string' &&
221 | 		typeof task.title === 'string' &&
222 | 		typeof task.description === 'string' &&
223 | 		isTaskStatus(task.status) &&
224 | 		isTaskPriority(task.priority) &&
225 | 		Array.isArray(task.dependencies) &&
226 | 		typeof task.details === 'string' &&
227 | 		typeof task.testStrategy === 'string' &&
228 | 		Array.isArray(task.subtasks)
229 | 	);
230 | }
231 | 
232 | /**
233 |  * Type guard to check if an object is a Subtask
234 |  */
235 | export function isSubtask(obj: unknown): obj is Subtask {
236 | 	if (!obj || typeof obj !== 'object') return false;
237 | 	const subtask = obj as Record<string, unknown>;
238 | 
239 | 	return (
240 | 		typeof subtask.id === 'number' &&
241 | 		typeof subtask.parentId === 'string' &&
242 | 		typeof subtask.title === 'string' &&
243 | 		typeof subtask.description === 'string' &&
244 | 		isTaskStatus(subtask.status) &&
245 | 		isTaskPriority(subtask.priority) &&
246 | 		!('subtasks' in subtask)
247 | 	);
248 | }
249 | 
250 | // ============================================================================
251 | // Deprecated Types (for backwards compatibility)
252 | // ============================================================================
253 | 
254 | /**
255 |  * @deprecated Use TaskStatus instead
256 |  */
257 | export type Status = TaskStatus;
258 | 
259 | /**
260 |  * @deprecated Use TaskPriority instead
261 |  */
262 | export type Priority = TaskPriority;
263 | 
264 | /**
265 |  * @deprecated Use TaskComplexity instead
266 |  */
267 | export type Complexity = TaskComplexity;
268 | 
```

--------------------------------------------------------------------------------
/apps/docs/capabilities/mcp.mdx:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: MCP Tools
  3 | sidebarTitle: "MCP Tools"
  4 | ---
  5 | 
  6 | # MCP Tools
  7 | 
  8 | This document provides an overview of the MCP (Machine-to-Machine Communication Protocol) interface for the Task Master application. The MCP interface is defined in the `mcp-server/` directory and exposes the application's core functionalities as a set of tools that can be called remotely.
  9 | 
 10 | ## Core Concepts
 11 | 
 12 | The MCP interface is built on top of the `fastmcp` library and registers a set of tools that correspond to the core functionalities of the Task Master application. These tools are defined in the `mcp-server/src/tools/` directory and are registered with the MCP server in `mcp-server/src/tools/index.js`.
 13 | 
 14 | Each tool is defined with a name, a description, and a set of parameters that are validated using the `zod` library. The `execute` function of each tool calls the corresponding core logic function from `scripts/modules/task-manager.js`.
 15 | 
 16 | ## Configurable Tool Loading
 17 | 
 18 | To optimize LLM context usage, you can control which Task Master MCP tools are loaded using the `TASK_MASTER_TOOLS` environment variable. This is particularly useful when working with LLMs that have context limits or when you only need a subset of tools.
 19 | 
 20 | ### Configuration Modes
 21 | 
 22 | #### All Tools (Default)
 23 | Loads all 36 available tools. Use when you need full Task Master functionality.
 24 | 
 25 | ```json
 26 | {
 27 |   "mcpServers": {
 28 |     "task-master-ai": {
 29 |       "command": "npx",
 30 |       "args": ["-y", "task-master-ai"],
 31 |       "env": {
 32 |         "TASK_MASTER_TOOLS": "all",
 33 |         "ANTHROPIC_API_KEY": "your_key_here"
 34 |       }
 35 |     }
 36 |   }
 37 | }
 38 | ```
 39 | 
 40 | If `TASK_MASTER_TOOLS` is not set, all tools are loaded by default.
 41 | 
 42 | #### Core Tools (Lean Mode)
 43 | Loads only 7 essential tools for daily development. Ideal for minimal context usage.
 44 | 
 45 | **Core tools included:**
 46 | - `get_tasks` - List all tasks
 47 | - `next_task` - Find the next task to work on
 48 | - `get_task` - Get detailed task information
 49 | - `set_task_status` - Update task status
 50 | - `update_subtask` - Add implementation notes
 51 | - `parse_prd` - Generate tasks from PRD
 52 | - `expand_task` - Break down tasks into subtasks
 53 | 
 54 | ```json
 55 | {
 56 |   "mcpServers": {
 57 |     "task-master-ai": {
 58 |       "command": "npx",
 59 |       "args": ["-y", "task-master-ai"],
 60 |       "env": {
 61 |         "TASK_MASTER_TOOLS": "core",
 62 |         "ANTHROPIC_API_KEY": "your_key_here"
 63 |       }
 64 |     }
 65 |   }
 66 | }
 67 | ```
 68 | 
 69 | You can also use `"lean"` as an alias for `"core"`.
 70 | 
 71 | #### Standard Tools
 72 | Loads 15 commonly used tools. Balances functionality with context efficiency.
 73 | 
 74 | **Standard tools include all core tools plus:**
 75 | - `initialize_project` - Set up new projects
 76 | - `analyze_project_complexity` - Analyze task complexity
 77 | - `expand_all` - Expand all eligible tasks
 78 | - `add_subtask` - Add subtasks manually
 79 | - `remove_task` - Remove tasks
 80 | - `generate` - Generate task markdown files
 81 | - `add_task` - Create new tasks
 82 | - `complexity_report` - View complexity analysis
 83 | 
 84 | ```json
 85 | {
 86 |   "mcpServers": {
 87 |     "task-master-ai": {
 88 |       "command": "npx",
 89 |       "args": ["-y", "task-master-ai"],
 90 |       "env": {
 91 |         "TASK_MASTER_TOOLS": "standard",
 92 |         "ANTHROPIC_API_KEY": "your_key_here"
 93 |       }
 94 |     }
 95 |   }
 96 | }
 97 | ```
 98 | 
 99 | #### Custom Tool Selection
100 | Specify exactly which tools to load using a comma-separated list. Tool names are case-insensitive and support both underscores and hyphens.
101 | 
102 | ```json
103 | {
104 |   "mcpServers": {
105 |     "task-master-ai": {
106 |       "command": "npx",
107 |       "args": ["-y", "task-master-ai"],
108 |       "env": {
109 |         "TASK_MASTER_TOOLS": "get_tasks,next_task,set_task_status,update_subtask",
110 |         "ANTHROPIC_API_KEY": "your_key_here"
111 |       }
112 |     }
113 |   }
114 | }
115 | ```
116 | 
117 | ### Choosing the Right Configuration
118 | 
119 | - **Use `core`/`lean`**: When working with basic task management workflows or when context limits are strict
120 | - **Use `standard`**: For most development workflows that include task creation and analysis
121 | - **Use `all`**: When you need full functionality including tag management, dependencies, and advanced features
122 | - **Use custom list**: When you have specific tool requirements or want to experiment with minimal sets
123 | 
124 | ### Verification
125 | 
126 | When the MCP server starts, it logs which tools were loaded:
127 | 
128 | ```
129 | Task Master MCP Server starting...
130 | Tool mode configuration: standard
131 | Loading standard tools
132 | Registering 15 MCP tools (mode: standard)
133 | Successfully registered 15/15 tools
134 | ```
135 | 
136 | ## Tool Categories
137 | 
138 | The MCP tools can be categorized in the same way as the core functionalities:
139 | 
140 | ### 1. Task and Subtask Management
141 | 
142 | -   **`add_task`**: Creates a new task.
143 | -   **`add_subtask`**: Adds a subtask to a parent task.
144 | -   **`remove_task`**: Removes one or more tasks or subtasks.
145 | -   **`remove_subtask`**: Removes a subtask from its parent.
146 | -   **`update_task`**: Updates a single task.
147 | -   **`update_subtask`**: Appends information to a subtask.
148 | -   **`update`**: Updates multiple tasks.
149 | -   **`move_task`**: Moves a task or subtask.
150 | -   **`clear_subtasks`**: Clears all subtasks from one or more tasks.
151 | 
152 | ### 2. Task Information and Status
153 | 
154 | -   **`get_tasks`**: Lists all tasks.
155 | -   **`get_task`**: Shows the details of a specific task.
156 | -   **`next_task`**: Shows the next task to work on.
157 | -   **`set_task_status`**: Sets the status of a task or subtask.
158 | 
159 | ### 3. Task Analysis and Expansion
160 | 
161 | -   **`parse_prd`**: Parses a PRD to generate tasks.
162 | -   **`expand_task`**: Expands a task into subtasks.
163 | -   **`expand_all`**: Expands all eligible tasks.
164 | -   **`analyze_project_complexity`**: Analyzes task complexity.
165 | -   **`complexity_report`**: Displays the complexity analysis report.
166 | 
167 | ### 4. Dependency Management
168 | 
169 | -   **`add_dependency`**: Adds a dependency to a task.
170 | -   **`remove_dependency`**: Removes a dependency from a task.
171 | -   **`validate_dependencies`**: Validates the dependencies of all tasks.
172 | -   **`fix_dependencies`**: Fixes any invalid dependencies.
173 | 
174 | ### 5. Project and Configuration
175 | 
176 | -   **`initialize_project`**: Initializes a new project.
177 | -   **`generate`**: Generates individual task files.
178 | -   **`models`**: Manages AI model configurations.
179 | -   **`research`**: Performs AI-powered research.
180 | 
181 | ### 6. Tag Management
182 | 
183 | -   **`add_tag`**: Creates a new tag.
184 | -   **`delete_tag`**: Deletes a tag.
185 | -   **`list_tags`**: Lists all tags.
186 | -   **`use_tag`**: Switches to a different tag.
187 | -   **`rename_tag`**: Renames a tag.
188 | -   **`copy_tag`**: Copies a tag.
```

--------------------------------------------------------------------------------
/tests/unit/profiles/rule-transformer-roo.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { jest } from '@jest/globals';
  2 | 
  3 | // Mock fs module before importing anything that uses it
  4 | jest.mock('fs', () => ({
  5 | 	readFileSync: jest.fn(),
  6 | 	writeFileSync: jest.fn(),
  7 | 	existsSync: jest.fn(),
  8 | 	mkdirSync: jest.fn()
  9 | }));
 10 | 
 11 | // Import modules after mocking
 12 | import fs from 'fs';
 13 | import { convertRuleToProfileRule } from '../../../src/utils/rule-transformer.js';
 14 | import { rooProfile } from '../../../src/profiles/roo.js';
 15 | 
 16 | describe('Roo Rule Transformer', () => {
 17 | 	// Set up spies on the mocked modules
 18 | 	const mockReadFileSync = jest.spyOn(fs, 'readFileSync');
 19 | 	const mockWriteFileSync = jest.spyOn(fs, 'writeFileSync');
 20 | 	const mockExistsSync = jest.spyOn(fs, 'existsSync');
 21 | 	const mockMkdirSync = jest.spyOn(fs, 'mkdirSync');
 22 | 	const mockConsoleError = jest
 23 | 		.spyOn(console, 'error')
 24 | 		.mockImplementation(() => {});
 25 | 
 26 | 	beforeEach(() => {
 27 | 		jest.clearAllMocks();
 28 | 		// Setup default mocks
 29 | 		mockReadFileSync.mockReturnValue('');
 30 | 		mockWriteFileSync.mockImplementation(() => {});
 31 | 		mockExistsSync.mockReturnValue(true);
 32 | 		mockMkdirSync.mockImplementation(() => {});
 33 | 	});
 34 | 
 35 | 	afterAll(() => {
 36 | 		jest.restoreAllMocks();
 37 | 	});
 38 | 
 39 | 	it('should correctly convert basic terms', () => {
 40 | 		const testContent = `---
 41 | description: Test Cursor rule for basic terms
 42 | globs: **/*
 43 | alwaysApply: true
 44 | ---
 45 | 
 46 | This is a Cursor rule that references cursor.so and uses the word Cursor multiple times.
 47 | Also has references to .mdc files.`;
 48 | 
 49 | 		// Mock file read to return our test content
 50 | 		mockReadFileSync.mockReturnValue(testContent);
 51 | 
 52 | 		// Call the actual function
 53 | 		const result = convertRuleToProfileRule(
 54 | 			'source.mdc',
 55 | 			'target.md',
 56 | 			rooProfile
 57 | 		);
 58 | 
 59 | 		// Verify the function succeeded
 60 | 		expect(result).toBe(true);
 61 | 
 62 | 		// Verify file operations were called correctly
 63 | 		expect(mockReadFileSync).toHaveBeenCalledWith('source.mdc', 'utf8');
 64 | 		expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
 65 | 
 66 | 		// Get the transformed content that was written
 67 | 		const writeCall = mockWriteFileSync.mock.calls[0];
 68 | 		const transformedContent = writeCall[1];
 69 | 
 70 | 		// Verify transformations
 71 | 		expect(transformedContent).toContain('Roo');
 72 | 		expect(transformedContent).toContain('roocode.com');
 73 | 		expect(transformedContent).toContain('.md');
 74 | 		expect(transformedContent).not.toContain('cursor.so');
 75 | 		expect(transformedContent).not.toContain('Cursor rule');
 76 | 	});
 77 | 
 78 | 	it('should correctly convert tool references', () => {
 79 | 		const testContent = `---
 80 | description: Test Cursor rule for tool references
 81 | globs: **/*
 82 | alwaysApply: true
 83 | ---
 84 | 
 85 | - Use the search tool to find code
 86 | - The edit_file tool lets you modify files
 87 | - run_command executes terminal commands
 88 | - use_mcp connects to external services`;
 89 | 
 90 | 		// Mock file read to return our test content
 91 | 		mockReadFileSync.mockReturnValue(testContent);
 92 | 
 93 | 		// Call the actual function
 94 | 		const result = convertRuleToProfileRule(
 95 | 			'source.mdc',
 96 | 			'target.md',
 97 | 			rooProfile
 98 | 		);
 99 | 
100 | 		// Verify the function succeeded
101 | 		expect(result).toBe(true);
102 | 
103 | 		// Get the transformed content that was written
104 | 		const writeCall = mockWriteFileSync.mock.calls[0];
105 | 		const transformedContent = writeCall[1];
106 | 
107 | 		// Verify transformations (Roo uses different tool names)
108 | 		expect(transformedContent).toContain('search_files tool');
109 | 		expect(transformedContent).toContain('apply_diff tool');
110 | 		expect(transformedContent).toContain('execute_command');
111 | 		expect(transformedContent).toContain('use_mcp_tool');
112 | 	});
113 | 
114 | 	it('should correctly update file references', () => {
115 | 		const testContent = `---
116 | description: Test Cursor rule for file references
117 | globs: **/*
118 | alwaysApply: true
119 | ---
120 | 
121 | This references [dev_workflow.mdc](mdc:.cursor/rules/dev_workflow.mdc) and 
122 | [taskmaster.mdc](mdc:.cursor/rules/taskmaster.mdc).`;
123 | 
124 | 		// Mock file read to return our test content
125 | 		mockReadFileSync.mockReturnValue(testContent);
126 | 
127 | 		// Call the actual function
128 | 		const result = convertRuleToProfileRule(
129 | 			'source.mdc',
130 | 			'target.md',
131 | 			rooProfile
132 | 		);
133 | 
134 | 		// Verify the function succeeded
135 | 		expect(result).toBe(true);
136 | 
137 | 		// Get the transformed content that was written
138 | 		const writeCall = mockWriteFileSync.mock.calls[0];
139 | 		const transformedContent = writeCall[1];
140 | 
141 | 		// Verify transformations - no taskmaster subdirectory for Roo
142 | 		expect(transformedContent).toContain('(.roo/rules/dev_workflow.md)'); // File path transformation - no taskmaster subdirectory for Roo
143 | 		expect(transformedContent).toContain('(.roo/rules/taskmaster.md)'); // File path transformation - no taskmaster subdirectory for Roo
144 | 		expect(transformedContent).not.toContain('(mdc:.cursor/rules/');
145 | 	});
146 | 
147 | 	it('should handle file read errors', () => {
148 | 		// Mock file read to throw an error
149 | 		mockReadFileSync.mockImplementation(() => {
150 | 			throw new Error('File not found');
151 | 		});
152 | 
153 | 		// Call the actual function
154 | 		const result = convertRuleToProfileRule(
155 | 			'nonexistent.mdc',
156 | 			'target.md',
157 | 			rooProfile
158 | 		);
159 | 
160 | 		// Verify the function failed gracefully
161 | 		expect(result).toBe(false);
162 | 
163 | 		// Verify writeFileSync was not called
164 | 		expect(mockWriteFileSync).not.toHaveBeenCalled();
165 | 
166 | 		// Verify error was logged
167 | 		expect(mockConsoleError).toHaveBeenCalledWith(
168 | 			'Error converting rule file: File not found'
169 | 		);
170 | 	});
171 | 
172 | 	it('should handle file write errors', () => {
173 | 		const testContent = 'test content';
174 | 		mockReadFileSync.mockReturnValue(testContent);
175 | 
176 | 		// Mock file write to throw an error
177 | 		mockWriteFileSync.mockImplementation(() => {
178 | 			throw new Error('Permission denied');
179 | 		});
180 | 
181 | 		// Call the actual function
182 | 		const result = convertRuleToProfileRule(
183 | 			'source.mdc',
184 | 			'target.md',
185 | 			rooProfile
186 | 		);
187 | 
188 | 		// Verify the function failed gracefully
189 | 		expect(result).toBe(false);
190 | 
191 | 		// Verify error was logged
192 | 		expect(mockConsoleError).toHaveBeenCalledWith(
193 | 			'Error converting rule file: Permission denied'
194 | 		);
195 | 	});
196 | 
197 | 	it('should create target directory if it does not exist', () => {
198 | 		const testContent = 'test content';
199 | 		mockReadFileSync.mockReturnValue(testContent);
200 | 
201 | 		// Mock directory doesn't exist initially
202 | 		mockExistsSync.mockReturnValue(false);
203 | 
204 | 		// Call the actual function
205 | 		convertRuleToProfileRule(
206 | 			'source.mdc',
207 | 			'some/deep/path/target.md',
208 | 			rooProfile
209 | 		);
210 | 
211 | 		// Verify directory creation was called
212 | 		expect(mockMkdirSync).toHaveBeenCalledWith('some/deep/path', {
213 | 			recursive: true
214 | 		});
215 | 	});
216 | });
217 | 
```
Page 19/69FirstPrevNextLast