#
tokens: 49806/50000 31/975 files (page 9/69)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 9 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

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/add-dependency.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * add-dependency.js
  3 |  * Direct function implementation for adding a dependency to a task
  4 |  */
  5 | 
  6 | import { addDependency } from '../../../../scripts/modules/dependency-manager.js';
  7 | import {
  8 | 	enableSilentMode,
  9 | 	disableSilentMode
 10 | } from '../../../../scripts/modules/utils.js';
 11 | 
 12 | /**
 13 |  * Direct function wrapper for addDependency with error handling.
 14 |  *
 15 |  * @param {Object} args - Command arguments
 16 |  * @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
 17 |  * @param {string|number} args.id - Task ID to add dependency to
 18 |  * @param {string|number} args.dependsOn - Task ID that will become a dependency
 19 |  * @param {string} args.tag - Tag for the task (optional)
 20 |  * @param {string} args.projectRoot - Project root path (for MCP/env fallback)
 21 |  * @param {Object} log - Logger object
 22 |  * @returns {Promise<Object>} - Result object with success status and data/error information
 23 |  */
 24 | export async function addDependencyDirect(args, log) {
 25 | 	// Destructure expected args
 26 | 	const { tasksJsonPath, id, dependsOn, tag, projectRoot } = args;
 27 | 	try {
 28 | 		log.info(`Adding dependency with args: ${JSON.stringify(args)}`);
 29 | 
 30 | 		// Check if tasksJsonPath was provided
 31 | 		if (!tasksJsonPath) {
 32 | 			log.error('addDependencyDirect called without tasksJsonPath');
 33 | 			return {
 34 | 				success: false,
 35 | 				error: {
 36 | 					code: 'MISSING_ARGUMENT',
 37 | 					message: 'tasksJsonPath is required'
 38 | 				}
 39 | 			};
 40 | 		}
 41 | 
 42 | 		// Validate required parameters
 43 | 		if (!id) {
 44 | 			return {
 45 | 				success: false,
 46 | 				error: {
 47 | 					code: 'INPUT_VALIDATION_ERROR',
 48 | 					message: 'Task ID (id) is required'
 49 | 				}
 50 | 			};
 51 | 		}
 52 | 
 53 | 		if (!dependsOn) {
 54 | 			return {
 55 | 				success: false,
 56 | 				error: {
 57 | 					code: 'INPUT_VALIDATION_ERROR',
 58 | 					message: 'Dependency ID (dependsOn) is required'
 59 | 				}
 60 | 			};
 61 | 		}
 62 | 
 63 | 		// Use provided path
 64 | 		const tasksPath = tasksJsonPath;
 65 | 
 66 | 		// Format IDs for the core function
 67 | 		const taskId =
 68 | 			id && id.includes && id.includes('.') ? id : parseInt(id, 10);
 69 | 		const dependencyId =
 70 | 			dependsOn && dependsOn.includes && dependsOn.includes('.')
 71 | 				? dependsOn
 72 | 				: parseInt(dependsOn, 10);
 73 | 
 74 | 		log.info(
 75 | 			`Adding dependency: task ${taskId} will depend on ${dependencyId}`
 76 | 		);
 77 | 
 78 | 		// Enable silent mode to prevent console logs from interfering with JSON response
 79 | 		enableSilentMode();
 80 | 
 81 | 		// Create context object
 82 | 		const context = { projectRoot, tag };
 83 | 
 84 | 		// Call the core function using the provided path
 85 | 		await addDependency(tasksPath, taskId, dependencyId, context);
 86 | 
 87 | 		// Restore normal logging
 88 | 		disableSilentMode();
 89 | 
 90 | 		return {
 91 | 			success: true,
 92 | 			data: {
 93 | 				message: `Successfully added dependency: Task ${taskId} now depends on ${dependencyId}`,
 94 | 				taskId: taskId,
 95 | 				dependencyId: dependencyId
 96 | 			}
 97 | 		};
 98 | 	} catch (error) {
 99 | 		// Make sure to restore normal logging even if there's an error
100 | 		disableSilentMode();
101 | 
102 | 		log.error(`Error in addDependencyDirect: ${error.message}`);
103 | 		return {
104 | 			success: false,
105 | 			error: {
106 | 				code: 'CORE_FUNCTION_ERROR',
107 | 				message: error.message
108 | 			}
109 | 		};
110 | 	}
111 | }
112 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/complexity-report.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * complexity-report.js
  3 |  * Direct function implementation for displaying complexity analysis report
  4 |  */
  5 | 
  6 | import {
  7 | 	readComplexityReport,
  8 | 	enableSilentMode,
  9 | 	disableSilentMode
 10 | } from '../../../../scripts/modules/utils.js';
 11 | 
 12 | /**
 13 |  * Direct function wrapper for displaying the complexity report with error handling and caching.
 14 |  *
 15 |  * @param {Object} args - Command arguments containing reportPath.
 16 |  * @param {string} args.reportPath - Explicit path to the complexity report file.
 17 |  * @param {Object} log - Logger object
 18 |  * @returns {Promise<Object>} - Result object with success status and data/error information
 19 |  */
 20 | export async function complexityReportDirect(args, log) {
 21 | 	// Destructure expected args
 22 | 	const { reportPath } = args;
 23 | 	try {
 24 | 		log.info(`Getting complexity report with args: ${JSON.stringify(args)}`);
 25 | 
 26 | 		// Check if reportPath was provided
 27 | 		if (!reportPath) {
 28 | 			log.error('complexityReportDirect called without reportPath');
 29 | 			return {
 30 | 				success: false,
 31 | 				error: { code: 'MISSING_ARGUMENT', message: 'reportPath is required' }
 32 | 			};
 33 | 		}
 34 | 
 35 | 		// Use the provided report path
 36 | 		log.info(`Looking for complexity report at: ${reportPath}`);
 37 | 
 38 | 		// Generate cache key based on report path
 39 | 		const cacheKey = `complexityReport:${reportPath}`;
 40 | 
 41 | 		// Define the core action function to read the report
 42 | 		const coreActionFn = async () => {
 43 | 			try {
 44 | 				// Enable silent mode to prevent console logs from interfering with JSON response
 45 | 				enableSilentMode();
 46 | 
 47 | 				const report = readComplexityReport(reportPath);
 48 | 
 49 | 				// Restore normal logging
 50 | 				disableSilentMode();
 51 | 
 52 | 				if (!report) {
 53 | 					log.warn(`No complexity report found at ${reportPath}`);
 54 | 					return {
 55 | 						success: false,
 56 | 						error: {
 57 | 							code: 'FILE_NOT_FOUND_ERROR',
 58 | 							message: `No complexity report found at ${reportPath}. Run 'analyze-complexity' first.`
 59 | 						}
 60 | 					};
 61 | 				}
 62 | 
 63 | 				return {
 64 | 					success: true,
 65 | 					data: {
 66 | 						report,
 67 | 						reportPath
 68 | 					}
 69 | 				};
 70 | 			} catch (error) {
 71 | 				// Make sure to restore normal logging even if there's an error
 72 | 				disableSilentMode();
 73 | 
 74 | 				log.error(`Error reading complexity report: ${error.message}`);
 75 | 				return {
 76 | 					success: false,
 77 | 					error: {
 78 | 						code: 'READ_ERROR',
 79 | 						message: error.message
 80 | 					}
 81 | 				};
 82 | 			}
 83 | 		};
 84 | 
 85 | 		// Use the caching utility
 86 | 		try {
 87 | 			const result = await coreActionFn();
 88 | 			log.info('complexityReportDirect completed');
 89 | 			return result;
 90 | 		} catch (error) {
 91 | 			// Ensure silent mode is disabled
 92 | 			disableSilentMode();
 93 | 
 94 | 			log.error(`Unexpected error during complexityReport: ${error.message}`);
 95 | 			return {
 96 | 				success: false,
 97 | 				error: {
 98 | 					code: 'UNEXPECTED_ERROR',
 99 | 					message: error.message
100 | 				}
101 | 			};
102 | 		}
103 | 	} catch (error) {
104 | 		// Ensure silent mode is disabled if an outer error occurs
105 | 		disableSilentMode();
106 | 
107 | 		log.error(`Error in complexityReportDirect: ${error.message}`);
108 | 		return {
109 | 			success: false,
110 | 			error: {
111 | 				code: 'UNEXPECTED_ERROR',
112 | 				message: error.message
113 | 			}
114 | 		};
115 | 	}
116 | }
117 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/logger.js:
--------------------------------------------------------------------------------

```javascript
  1 | import chalk from 'chalk';
  2 | import { isSilentMode } from '../../scripts/modules/utils.js';
  3 | import { getLogLevel } from '../../scripts/modules/config-manager.js';
  4 | 
  5 | // Define log levels
  6 | const LOG_LEVELS = {
  7 | 	debug: 0,
  8 | 	info: 1,
  9 | 	warn: 2,
 10 | 	error: 3,
 11 | 	success: 4
 12 | };
 13 | 
 14 | // Get log level from config manager or default to info
 15 | const LOG_LEVEL = LOG_LEVELS[getLogLevel().toLowerCase()] ?? LOG_LEVELS.info;
 16 | 
 17 | /**
 18 |  * Logs a message with the specified level
 19 |  * @param {string} level - The log level (debug, info, warn, error, success)
 20 |  * @param  {...any} args - Arguments to log
 21 |  */
 22 | function log(level, ...args) {
 23 | 	// Skip logging if silent mode is enabled
 24 | 	if (isSilentMode()) {
 25 | 		return;
 26 | 	}
 27 | 
 28 | 	// Use text prefixes instead of emojis
 29 | 	const prefixes = {
 30 | 		debug: chalk.gray('[DEBUG]'),
 31 | 		info: chalk.blue('[INFO]'),
 32 | 		warn: chalk.yellow('[WARN]'),
 33 | 		error: chalk.red('[ERROR]'),
 34 | 		success: chalk.green('[SUCCESS]')
 35 | 	};
 36 | 
 37 | 	if (LOG_LEVELS[level] !== undefined && LOG_LEVELS[level] >= LOG_LEVEL) {
 38 | 		const prefix = prefixes[level] || '';
 39 | 		let coloredArgs = args;
 40 | 
 41 | 		try {
 42 | 			switch (level) {
 43 | 				case 'error':
 44 | 					coloredArgs = args.map((arg) =>
 45 | 						typeof arg === 'string' ? chalk.red(arg) : arg
 46 | 					);
 47 | 					break;
 48 | 				case 'warn':
 49 | 					coloredArgs = args.map((arg) =>
 50 | 						typeof arg === 'string' ? chalk.yellow(arg) : arg
 51 | 					);
 52 | 					break;
 53 | 				case 'success':
 54 | 					coloredArgs = args.map((arg) =>
 55 | 						typeof arg === 'string' ? chalk.green(arg) : arg
 56 | 					);
 57 | 					break;
 58 | 				case 'info':
 59 | 					coloredArgs = args.map((arg) =>
 60 | 						typeof arg === 'string' ? chalk.blue(arg) : arg
 61 | 					);
 62 | 					break;
 63 | 				case 'debug':
 64 | 					coloredArgs = args.map((arg) =>
 65 | 						typeof arg === 'string' ? chalk.gray(arg) : arg
 66 | 					);
 67 | 					break;
 68 | 				// default: use original args (no color)
 69 | 			}
 70 | 		} catch (colorError) {
 71 | 			// Fallback if chalk fails on an argument
 72 | 			// Use console.error here for internal logger errors, separate from normal logging
 73 | 			console.error('Internal Logger Error applying chalk color:', colorError);
 74 | 			coloredArgs = args;
 75 | 		}
 76 | 
 77 | 		// Revert to console.log - FastMCP's context logger (context.log)
 78 | 		// is responsible for directing logs correctly (e.g., to stderr)
 79 | 		// during tool execution without upsetting the client connection.
 80 | 		// Logs outside of tool execution (like startup) will go to stdout.
 81 | 		console.error(prefix, ...coloredArgs);
 82 | 	}
 83 | }
 84 | 
 85 | /**
 86 |  * Create a logger object with methods for different log levels
 87 |  * @returns {Object} Logger object with info, error, debug, warn, and success methods
 88 |  */
 89 | export function createLogger() {
 90 | 	const createLogMethod =
 91 | 		(level) =>
 92 | 		(...args) =>
 93 | 			log(level, ...args);
 94 | 
 95 | 	return {
 96 | 		debug: createLogMethod('debug'),
 97 | 		info: createLogMethod('info'),
 98 | 		warn: createLogMethod('warn'),
 99 | 		error: createLogMethod('error'),
100 | 		success: createLogMethod('success'),
101 | 		log: log // Also expose the raw log function
102 | 	};
103 | }
104 | 
105 | // Export a default logger instance
106 | const logger = createLogger();
107 | 
108 | export default logger;
109 | export { log, LOG_LEVELS };
110 | 
```

--------------------------------------------------------------------------------
/apps/extension/src/webview/App.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Main App Component
  3 |  */
  4 | 
  5 | import React, { useReducer, useState, useEffect, useRef } from 'react';
  6 | import { VSCodeContext } from './contexts/VSCodeContext';
  7 | import { QueryProvider } from './providers/QueryProvider';
  8 | import { AppContent } from './components/AppContent';
  9 | import { ToastContainer } from './components/ToastContainer';
 10 | import { ErrorBoundary } from './components/ErrorBoundary';
 11 | import { appReducer, initialState } from './reducers/appReducer';
 12 | import { useWebviewHeight } from './hooks/useWebviewHeight';
 13 | import { useVSCodeMessages } from './hooks/useVSCodeMessages';
 14 | import {
 15 | 	showSuccessToast,
 16 | 	showInfoToast,
 17 | 	showWarningToast,
 18 | 	showErrorToast,
 19 | 	createToast
 20 | } from './utils/toast';
 21 | 
 22 | export const App: React.FC = () => {
 23 | 	const [state, dispatch] = useReducer(appReducer, initialState);
 24 | 	const [vscode] = useState(() => window.acquireVsCodeApi?.());
 25 | 	const availableHeight = useWebviewHeight();
 26 | 	const { sendMessage } = useVSCodeMessages(vscode, state, dispatch);
 27 | 	const hasInitialized = useRef(false);
 28 | 
 29 | 	// Initialize the webview
 30 | 	useEffect(() => {
 31 | 		if (hasInitialized.current) return;
 32 | 		hasInitialized.current = true;
 33 | 
 34 | 		if (!vscode) {
 35 | 			console.warn('⚠️ VS Code API not available - running in standalone mode');
 36 | 			dispatch({
 37 | 				type: 'SET_CONNECTION_STATUS',
 38 | 				payload: { isConnected: false, status: 'Standalone Mode' }
 39 | 			});
 40 | 			return;
 41 | 		}
 42 | 
 43 | 		console.log('🔄 Initializing webview...');
 44 | 
 45 | 		// Notify extension that webview is ready
 46 | 		vscode.postMessage({ type: 'ready' });
 47 | 
 48 | 		// React Query will handle task fetching, so we only need to load tags data
 49 | 		sendMessage({ type: 'getTags' })
 50 | 			.then((tagsData) => {
 51 | 				if (tagsData?.tags && tagsData?.currentTag) {
 52 | 					const tagNames = tagsData.tags.map((tag: any) => tag.name || tag);
 53 | 					dispatch({
 54 | 						type: 'SET_TAG_DATA',
 55 | 						payload: {
 56 | 							currentTag: tagsData.currentTag,
 57 | 							availableTags: tagNames
 58 | 						}
 59 | 					});
 60 | 				}
 61 | 			})
 62 | 			.catch((error) => {
 63 | 				console.error('❌ Failed to load tags:', error);
 64 | 			});
 65 | 	}, [vscode, sendMessage, dispatch]);
 66 | 
 67 | 	const contextValue = {
 68 | 		vscode,
 69 | 		state,
 70 | 		dispatch,
 71 | 		sendMessage,
 72 | 		availableHeight,
 73 | 		// Toast notification functions
 74 | 		showSuccessToast: showSuccessToast(dispatch),
 75 | 		showInfoToast: showInfoToast(dispatch),
 76 | 		showWarningToast: showWarningToast(dispatch),
 77 | 		showErrorToast: showErrorToast(dispatch)
 78 | 	};
 79 | 
 80 | 	return (
 81 | 		<QueryProvider>
 82 | 			<VSCodeContext.Provider value={contextValue}>
 83 | 				<ErrorBoundary
 84 | 					onError={(error) => {
 85 | 						// Handle React errors and show appropriate toast
 86 | 						dispatch({
 87 | 							type: 'ADD_TOAST',
 88 | 							payload: createToast(
 89 | 								'error',
 90 | 								'Component Error',
 91 | 								`A React component crashed: ${error.message}`,
 92 | 								10000
 93 | 							)
 94 | 						});
 95 | 					}}
 96 | 				>
 97 | 					<AppContent />
 98 | 					<ToastContainer
 99 | 						notifications={state.toastNotifications}
100 | 						onDismiss={(id) => dispatch({ type: 'REMOVE_TOAST', payload: id })}
101 | 					/>
102 | 				</ErrorBoundary>
103 | 			</VSCodeContext.Provider>
104 | 		</QueryProvider>
105 | 	);
106 | };
107 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/tools/research.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * tools/research.js
  3 |  * Tool to perform AI-powered research queries with project context
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	createErrorResponse,
  9 | 	handleApiResult,
 10 | 	withNormalizedProjectRoot
 11 | } from './utils.js';
 12 | import { researchDirect } from '../core/task-master-core.js';
 13 | import { resolveTag } from '../../../scripts/modules/utils.js';
 14 | 
 15 | /**
 16 |  * Register the research tool with the MCP server
 17 |  * @param {Object} server - FastMCP server instance
 18 |  */
 19 | export function registerResearchTool(server) {
 20 | 	server.addTool({
 21 | 		name: 'research',
 22 | 		description: 'Perform AI-powered research queries with project context',
 23 | 
 24 | 		parameters: z.object({
 25 | 			query: z.string().describe('Research query/prompt (required)'),
 26 | 			taskIds: z
 27 | 				.string()
 28 | 				.optional()
 29 | 				.describe(
 30 | 					'Comma-separated list of task/subtask IDs for context (e.g., "15,16.2,17")'
 31 | 				),
 32 | 			filePaths: z
 33 | 				.string()
 34 | 				.optional()
 35 | 				.describe(
 36 | 					'Comma-separated list of file paths for context (e.g., "src/api.js,docs/readme.md")'
 37 | 				),
 38 | 			customContext: z
 39 | 				.string()
 40 | 				.optional()
 41 | 				.describe('Additional custom context text to include in the research'),
 42 | 			includeProjectTree: z
 43 | 				.boolean()
 44 | 				.optional()
 45 | 				.describe(
 46 | 					'Include project file tree structure in context (default: false)'
 47 | 				),
 48 | 			detailLevel: z
 49 | 				.enum(['low', 'medium', 'high'])
 50 | 				.optional()
 51 | 				.describe('Detail level for the research response (default: medium)'),
 52 | 			saveTo: z
 53 | 				.string()
 54 | 				.optional()
 55 | 				.describe(
 56 | 					'Automatically save research results to specified task/subtask ID (e.g., "15" or "15.2")'
 57 | 				),
 58 | 			saveToFile: z
 59 | 				.boolean()
 60 | 				.optional()
 61 | 				.describe(
 62 | 					'Save research results to .taskmaster/docs/research/ directory (default: false)'
 63 | 				),
 64 | 			projectRoot: z
 65 | 				.string()
 66 | 				.describe('The directory of the project. Must be an absolute path.'),
 67 | 			tag: z.string().optional().describe('Tag context to operate on')
 68 | 		}),
 69 | 		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
 70 | 			try {
 71 | 				const resolvedTag = resolveTag({
 72 | 					projectRoot: args.projectRoot,
 73 | 					tag: args.tag
 74 | 				});
 75 | 				log.info(
 76 | 					`Starting research with query: "${args.query.substring(0, 100)}${args.query.length > 100 ? '...' : ''}"`
 77 | 				);
 78 | 
 79 | 				// Call the direct function
 80 | 				const result = await researchDirect(
 81 | 					{
 82 | 						query: args.query,
 83 | 						taskIds: args.taskIds,
 84 | 						filePaths: args.filePaths,
 85 | 						customContext: args.customContext,
 86 | 						includeProjectTree: args.includeProjectTree || false,
 87 | 						detailLevel: args.detailLevel || 'medium',
 88 | 						saveTo: args.saveTo,
 89 | 						saveToFile: args.saveToFile || false,
 90 | 						projectRoot: args.projectRoot,
 91 | 						tag: resolvedTag
 92 | 					},
 93 | 					log,
 94 | 					{ session }
 95 | 				);
 96 | 
 97 | 				return handleApiResult(
 98 | 					result,
 99 | 					log,
100 | 					'Error performing research',
101 | 					undefined,
102 | 					args.projectRoot
103 | 				);
104 | 			} catch (error) {
105 | 				log.error(`Error in research tool: ${error.message}`);
106 | 				return createErrorResponse(error.message);
107 | 			}
108 | 		})
109 | 	});
110 | }
111 | 
```

--------------------------------------------------------------------------------
/apps/mcp/src/tools/autopilot/finalize.tool.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview autopilot-finalize MCP tool
  3 |  * Finalize and complete the workflow with working tree validation
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	handleApiResult,
  9 | 	withNormalizedProjectRoot
 10 | } from '../../shared/utils.js';
 11 | import type { MCPContext } from '../../shared/types.js';
 12 | import { WorkflowService } from '@tm/core';
 13 | import type { FastMCP } from 'fastmcp';
 14 | 
 15 | const FinalizeSchema = z.object({
 16 | 	projectRoot: z
 17 | 		.string()
 18 | 		.describe('Absolute path to the project root directory')
 19 | });
 20 | 
 21 | type FinalizeArgs = z.infer<typeof FinalizeSchema>;
 22 | 
 23 | /**
 24 |  * Register the autopilot_finalize tool with the MCP server
 25 |  */
 26 | export function registerAutopilotFinalizeTool(server: FastMCP) {
 27 | 	server.addTool({
 28 | 		name: 'autopilot_finalize',
 29 | 		description:
 30 | 			'Finalize and complete the workflow. Validates that all changes are committed and working tree is clean before marking workflow as complete.',
 31 | 		parameters: FinalizeSchema,
 32 | 		execute: withNormalizedProjectRoot(
 33 | 			async (args: FinalizeArgs, context: MCPContext) => {
 34 | 				const { projectRoot } = args;
 35 | 
 36 | 				try {
 37 | 					context.log.info(`Finalizing workflow in ${projectRoot}`);
 38 | 
 39 | 					const workflowService = new WorkflowService(projectRoot);
 40 | 
 41 | 					// Check if workflow exists
 42 | 					if (!(await workflowService.hasWorkflow())) {
 43 | 						return handleApiResult({
 44 | 							result: {
 45 | 								success: false,
 46 | 								error: {
 47 | 									message:
 48 | 										'No active workflow found. Start a workflow with autopilot_start'
 49 | 								}
 50 | 							},
 51 | 							log: context.log,
 52 | 							projectRoot
 53 | 						});
 54 | 					}
 55 | 
 56 | 					// Resume workflow
 57 | 					await workflowService.resumeWorkflow();
 58 | 					const currentStatus = workflowService.getStatus();
 59 | 
 60 | 					// Verify we're in FINALIZE phase
 61 | 					if (currentStatus.phase !== 'FINALIZE') {
 62 | 						return handleApiResult({
 63 | 							result: {
 64 | 								success: false,
 65 | 								error: {
 66 | 									message: `Cannot finalize: workflow is in ${currentStatus.phase} phase. Complete all subtasks first.`
 67 | 								}
 68 | 							},
 69 | 							log: context.log,
 70 | 							projectRoot
 71 | 						});
 72 | 					}
 73 | 
 74 | 					// Finalize workflow (validates clean working tree)
 75 | 					const newStatus = await workflowService.finalizeWorkflow();
 76 | 
 77 | 					context.log.info('Workflow finalized successfully');
 78 | 
 79 | 					// Get next action
 80 | 					const nextAction = workflowService.getNextAction();
 81 | 
 82 | 					return handleApiResult({
 83 | 						result: {
 84 | 							success: true,
 85 | 							data: {
 86 | 								message: 'Workflow completed successfully',
 87 | 								...newStatus,
 88 | 								nextAction: nextAction.action,
 89 | 								nextSteps: nextAction.nextSteps
 90 | 							}
 91 | 						},
 92 | 						log: context.log,
 93 | 						projectRoot
 94 | 					});
 95 | 				} catch (error: any) {
 96 | 					context.log.error(`Error in autopilot-finalize: ${error.message}`);
 97 | 					if (error.stack) {
 98 | 						context.log.debug(error.stack);
 99 | 					}
100 | 					return handleApiResult({
101 | 						result: {
102 | 							success: false,
103 | 							error: {
104 | 								message: `Failed to finalize workflow: ${error.message}`
105 | 							}
106 | 						},
107 | 						log: context.log,
108 | 						projectRoot
109 | 					});
110 | 				}
111 | 			}
112 | 		)
113 | 	});
114 | }
115 | 
```

--------------------------------------------------------------------------------
/apps/docs/archive/Installation.mdx:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "Installation(2)"
  3 | description: "This guide walks you through setting up Task Master in your development environment."
  4 | ---
  5 | 
  6 | ## Initial Setup
  7 | 
  8 | <Tip>
  9 |   MCP (Model Control Protocol) provides the easiest way to get started with Task Master directly in your editor.
 10 | </Tip>
 11 | 
 12 | <AccordionGroup>
 13 |   <Accordion title="Option 1: Using MCP (Recommended)" icon="sparkles">
 14 |     <Steps>
 15 |       <Step title="Add the MCP config to your editor">
 16 |         <Link href="https://cursor.sh">Cursor</Link> recommended, but it works with other text editors
 17 |         ```json
 18 |         {
 19 |         	"mcpServers": {
 20 |         		"taskmaster-ai": {
 21 |         			"command": "npx",
 22 |         			"args": ["-y", "task-master-ai"],
 23 |         			"env": {
 24 |         				"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
 25 |         				"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",
 26 |         				"MODEL": "claude-3-7-sonnet-20250219",
 27 |         				"PERPLEXITY_MODEL": "sonar-pro",
 28 |         				"MAX_TOKENS": 128000,
 29 |         				"TEMPERATURE": 0.2,
 30 |         				"DEFAULT_SUBTASKS": 5,
 31 |         				"DEFAULT_PRIORITY": "medium"
 32 |         			}
 33 |         		}
 34 |         	}
 35 |         }
 36 |         ```
 37 |       </Step>
 38 |       <Step title="Enable the MCP in your editor settings">
 39 |         
 40 |       </Step>
 41 |       <Step title="Prompt the AI to initialize Task Master">
 42 |         > "Can you please initialize taskmaster-ai into my project?"
 43 | 
 44 |         **The AI will:**
 45 | 
 46 |         1. Create necessary project structure
 47 |         2. Set up initial configuration files
 48 |         3. Guide you through the rest of the process
 49 |         4. Place your PRD document in the `scripts/` directory (e.g., `scripts/prd.txt`)
 50 |         5. **Use natural language commands** to interact with Task Master:
 51 | 
 52 |            > "Can you parse my PRD at scripts/prd.txt?"
 53 |            >
 54 |            > "What's the next task I should work on?"
 55 |            >
 56 |            > "Can you help me implement task 3?"
 57 |       </Step>
 58 |     </Steps>
 59 |   </Accordion>
 60 |   <Accordion title="Option 2: Manual Installation">
 61 |     If you prefer to use the command line interface directly:
 62 | 
 63 |     <Steps>
 64 |       <Step title="Install">
 65 |         <CodeGroup>
 66 | 
 67 |         ```bash Global
 68 |         npm install -g task-master-ai
 69 |         ```
 70 | 
 71 |         
 72 |         ```bash Local
 73 |         npm install task-master-ai
 74 |         ```
 75 | 
 76 |         </CodeGroup>
 77 |       </Step>
 78 |       <Step title="Initialize a new project">
 79 |         <CodeGroup>
 80 | 
 81 |         ```bash Global
 82 |         task-master init
 83 |         ```
 84 | 
 85 |         
 86 |         ```bash Local
 87 |         npx task-master-init
 88 |         ```
 89 | 
 90 |         </CodeGroup>
 91 |       </Step>
 92 |     </Steps>
 93 |     This will prompt you for project details and set up a new project with the necessary files and structure.
 94 |   </Accordion>
 95 | </AccordionGroup>
 96 | 
 97 | ## Common Commands
 98 | 
 99 | <Tip>
100 |   After setting up Task Master, you can use these commands (either via AI prompts or CLI)
101 | </Tip>
102 | 
103 | ```bash
104 | # Parse a PRD and generate tasks
105 | task-master parse-prd your-prd.txt
106 | 
107 | # List all tasks
108 | task-master list
109 | 
110 | # Show the next task to work on
111 | task-master next
112 | 
113 | # Generate task files
114 | task-master generate 
115 | 
```

--------------------------------------------------------------------------------
/packages/tm-core/src/common/constants/paths.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * @fileoverview Path constants for Task Master Core
 3 |  * Defines all file paths and directory structure constants
 4 |  */
 5 | 
 6 | // .taskmaster directory structure paths
 7 | export const TASKMASTER_DIR = '.taskmaster';
 8 | export const TASKMASTER_TASKS_DIR = '.taskmaster/tasks';
 9 | export const TASKMASTER_DOCS_DIR = '.taskmaster/docs';
10 | export const TASKMASTER_REPORTS_DIR = '.taskmaster/reports';
11 | export const TASKMASTER_TEMPLATES_DIR = '.taskmaster/templates';
12 | 
13 | // Task Master configuration files
14 | export const TASKMASTER_CONFIG_FILE = '.taskmaster/config.json';
15 | export const TASKMASTER_STATE_FILE = '.taskmaster/state.json';
16 | export const LEGACY_CONFIG_FILE = '.taskmasterconfig';
17 | 
18 | // Task Master report files
19 | export const COMPLEXITY_REPORT_FILE =
20 | 	'.taskmaster/reports/task-complexity-report.json';
21 | export const LEGACY_COMPLEXITY_REPORT_FILE =
22 | 	'scripts/task-complexity-report.json';
23 | 
24 | // Task Master PRD file paths
25 | export const PRD_FILE = '.taskmaster/docs/prd.txt';
26 | export const LEGACY_PRD_FILE = 'scripts/prd.txt';
27 | 
28 | // Task Master template files
29 | export const EXAMPLE_PRD_FILE = '.taskmaster/templates/example_prd.txt';
30 | export const LEGACY_EXAMPLE_PRD_FILE = 'scripts/example_prd.txt';
31 | 
32 | // Task Master task file paths
33 | export const TASKMASTER_TASKS_FILE = '.taskmaster/tasks/tasks.json';
34 | export const LEGACY_TASKS_FILE = 'tasks/tasks.json';
35 | 
36 | // General project files (not Task Master specific but commonly used)
37 | export const ENV_EXAMPLE_FILE = '.env.example';
38 | export const GITIGNORE_FILE = '.gitignore';
39 | 
40 | // Task file naming pattern
41 | export const TASK_FILE_PREFIX = 'task_';
42 | export const TASK_FILE_EXTENSION = '.txt';
43 | 
44 | /**
45 |  * Task Master specific markers (absolute highest priority)
46 |  * ONLY truly Task Master-specific markers that uniquely identify a Task Master project
47 |  */
48 | export const TASKMASTER_PROJECT_MARKERS = [
49 | 	'.taskmaster', // Task Master directory
50 | 	TASKMASTER_CONFIG_FILE, // .taskmaster/config.json
51 | 	TASKMASTER_TASKS_FILE, // .taskmaster/tasks/tasks.json
52 | 	LEGACY_CONFIG_FILE // .taskmasterconfig (legacy but still Task Master-specific)
53 | ] as const;
54 | 
55 | /**
56 |  * Other project markers (only checked if no Task Master markers found)
57 |  * Includes generic task files that could belong to any task runner/build system
58 |  */
59 | export const OTHER_PROJECT_MARKERS = [
60 | 	LEGACY_TASKS_FILE, // tasks/tasks.json (NOT Task Master-specific)
61 | 	'tasks.json', // Generic tasks file (NOT Task Master-specific)
62 | 	'.git', // Git repository
63 | 	'.svn', // SVN repository
64 | 	'package.json', // Node.js project
65 | 	'yarn.lock', // Yarn project
66 | 	'package-lock.json', // npm project
67 | 	'pnpm-lock.yaml', // pnpm project
68 | 	'Cargo.toml', // Rust project
69 | 	'go.mod', // Go project
70 | 	'pyproject.toml', // Python project
71 | 	'requirements.txt', // Python project
72 | 	'Gemfile', // Ruby project
73 | 	'composer.json' // PHP project
74 | ] as const;
75 | 
76 | /**
77 |  * All project markers combined (for backward compatibility)
78 |  * @deprecated Use TASKMASTER_PROJECT_MARKERS and OTHER_PROJECT_MARKERS separately
79 |  */
80 | export const PROJECT_MARKERS = [
81 | 	...TASKMASTER_PROJECT_MARKERS,
82 | 	...OTHER_PROJECT_MARKERS
83 | ] as const;
84 | 
```

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

```typescript
  1 | /**
  2 |  * @fileoverview Constants for Task Master Core
  3 |  * Single source of truth for all constant values
  4 |  */
  5 | 
  6 | import type {
  7 | 	TaskComplexity,
  8 | 	TaskPriority,
  9 | 	TaskStatus
 10 | } from '../types/index.js';
 11 | 
 12 | // Import from root package.json (monorepo root) for version info
 13 | import packageJson from '../../../../../package.json' with { type: 'json' };
 14 | 
 15 | /**
 16 |  * Task Master version from root package.json
 17 |  * Centralized to avoid fragile relative paths throughout the codebase
 18 |  */
 19 | export const TASKMASTER_VERSION = packageJson.version || 'unknown';
 20 | 
 21 | /**
 22 |  * Package name from root package.json
 23 |  */
 24 | export const PACKAGE_NAME = packageJson.name || 'task-master-ai';
 25 | 
 26 | /**
 27 |  * Valid task status values
 28 |  */
 29 | export const TASK_STATUSES: readonly TaskStatus[] = [
 30 | 	'pending',
 31 | 	'in-progress',
 32 | 	'done',
 33 | 	'deferred',
 34 | 	'cancelled',
 35 | 	'blocked',
 36 | 	'review'
 37 | ] as const;
 38 | 
 39 | /**
 40 |  * Terminal complete statuses - tasks that are finished and satisfy dependencies
 41 |  * These statuses indicate a task is in a final state and:
 42 |  * - Should count toward completion percentage
 43 |  * - Should be considered satisfied for dependency resolution
 44 |  * - Should not be selected as "next task"
 45 |  *
 46 |  * Note: 'completed' is a workflow-specific alias for 'done' used in some contexts
 47 |  */
 48 | export const TERMINAL_COMPLETE_STATUSES: readonly TaskStatus[] = [
 49 | 	'done',
 50 | 	'completed',
 51 | 	'cancelled'
 52 | ] as const;
 53 | 
 54 | /**
 55 |  * Check if a task status represents a terminal complete state
 56 |  *
 57 |  * @param status - The task status to check
 58 |  * @returns true if the status represents a completed/terminal task
 59 |  *
 60 |  * @example
 61 |  * ```typescript
 62 |  * isTaskComplete('done')      // true
 63 |  * isTaskComplete('completed') // true
 64 |  * isTaskComplete('cancelled') // true
 65 |  * isTaskComplete('pending')   // false
 66 |  * ```
 67 |  */
 68 | export function isTaskComplete(status: TaskStatus): boolean {
 69 | 	return TERMINAL_COMPLETE_STATUSES.includes(status);
 70 | }
 71 | 
 72 | /**
 73 |  * Valid task priority values
 74 |  */
 75 | export const TASK_PRIORITIES: readonly TaskPriority[] = [
 76 | 	'low',
 77 | 	'medium',
 78 | 	'high',
 79 | 	'critical'
 80 | ] as const;
 81 | 
 82 | /**
 83 |  * Valid task complexity values
 84 |  */
 85 | export const TASK_COMPLEXITIES: readonly TaskComplexity[] = [
 86 | 	'simple',
 87 | 	'moderate',
 88 | 	'complex',
 89 | 	'very-complex'
 90 | ] as const;
 91 | 
 92 | /**
 93 |  * Valid output formats for task display
 94 |  */
 95 | export const OUTPUT_FORMATS = ['text', 'json', 'compact'] as const;
 96 | export type OutputFormat = (typeof OUTPUT_FORMATS)[number];
 97 | 
 98 | /**
 99 |  * Status icons for display
100 |  */
101 | export const STATUS_ICONS: Record<TaskStatus, string> = {
102 | 	done: '✓',
103 | 	completed: '✓',
104 | 	'in-progress': '►',
105 | 	blocked: '⭕',
106 | 	pending: '○',
107 | 	deferred: '⏸',
108 | 	cancelled: '✗',
109 | 	review: '👁'
110 | } as const;
111 | 
112 | /**
113 |  * Status colors for display (using chalk color names)
114 |  */
115 | export const STATUS_COLORS: Record<TaskStatus, string> = {
116 | 	pending: 'yellow',
117 | 	'in-progress': 'blue',
118 | 	done: 'green',
119 | 	deferred: 'gray',
120 | 	cancelled: 'red',
121 | 	blocked: 'magenta',
122 | 	review: 'cyan',
123 | 	completed: 'green'
124 | } as const;
125 | 
126 | /**
127 |  * Provider constants - AI model providers
128 |  */
129 | export * from './providers.js';
130 | 
131 | /**
132 |  * Path constants - file paths and directory structure
133 |  */
134 | export * from './paths.js';
135 | 
```

--------------------------------------------------------------------------------
/packages/tm-core/src/modules/workflow/types.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Workflow phase definitions
  3 |  */
  4 | export type WorkflowPhase =
  5 | 	| 'PREFLIGHT'
  6 | 	| 'BRANCH_SETUP'
  7 | 	| 'SUBTASK_LOOP'
  8 | 	| 'FINALIZE'
  9 | 	| 'COMPLETE';
 10 | 
 11 | /**
 12 |  * TDD cycle phases within subtask loop
 13 |  */
 14 | export type TDDPhase = 'RED' | 'GREEN' | 'COMMIT';
 15 | 
 16 | /**
 17 |  * Workflow state context
 18 |  */
 19 | export interface WorkflowContext {
 20 | 	taskId: string;
 21 | 	subtasks: SubtaskInfo[];
 22 | 	currentSubtaskIndex: number;
 23 | 	currentTDDPhase?: TDDPhase;
 24 | 	branchName?: string;
 25 | 	errors: WorkflowError[];
 26 | 	metadata: Record<string, unknown>;
 27 | 	lastTestResults?: TestResult;
 28 | }
 29 | 
 30 | /**
 31 |  * Test result from test execution
 32 |  */
 33 | export interface TestResult {
 34 | 	total: number;
 35 | 	passed: number;
 36 | 	failed: number;
 37 | 	skipped: number;
 38 | 	phase: 'RED' | 'GREEN';
 39 | }
 40 | 
 41 | /**
 42 |  * Subtask information
 43 |  */
 44 | export interface SubtaskInfo {
 45 | 	id: string;
 46 | 	title: string;
 47 | 	status: 'pending' | 'in-progress' | 'completed' | 'failed';
 48 | 	attempts: number;
 49 | 	maxAttempts?: number;
 50 | }
 51 | 
 52 | /**
 53 |  * Workflow error information
 54 |  */
 55 | export interface WorkflowError {
 56 | 	phase: WorkflowPhase;
 57 | 	message: string;
 58 | 	timestamp: Date;
 59 | 	recoverable: boolean;
 60 | }
 61 | 
 62 | /**
 63 |  * State machine state
 64 |  */
 65 | export interface WorkflowState {
 66 | 	phase: WorkflowPhase;
 67 | 	context: WorkflowContext;
 68 | }
 69 | 
 70 | /**
 71 |  * State transition event types
 72 |  */
 73 | export type WorkflowEvent =
 74 | 	| { type: 'PREFLIGHT_COMPLETE' }
 75 | 	| { type: 'BRANCH_CREATED'; branchName: string }
 76 | 	| { type: 'SUBTASK_START'; subtaskId: string }
 77 | 	| { type: 'RED_PHASE_COMPLETE'; testResults?: TestResult }
 78 | 	| { type: 'GREEN_PHASE_COMPLETE'; testResults?: TestResult }
 79 | 	| { type: 'COMMIT_COMPLETE' }
 80 | 	| { type: 'SUBTASK_COMPLETE' }
 81 | 	| { type: 'ALL_SUBTASKS_COMPLETE' }
 82 | 	| { type: 'FINALIZE_COMPLETE' }
 83 | 	| { type: 'ERROR'; error: WorkflowError }
 84 | 	| { type: 'RETRY' }
 85 | 	| { type: 'ABORT' };
 86 | 
 87 | /**
 88 |  * State transition definition
 89 |  */
 90 | export interface StateTransition {
 91 | 	from: WorkflowPhase;
 92 | 	to: WorkflowPhase;
 93 | 	event: WorkflowEvent['type'];
 94 | 	guard?: (context: WorkflowContext) => boolean;
 95 | }
 96 | 
 97 | /**
 98 |  * State machine configuration
 99 |  */
100 | export interface StateMachineConfig {
101 | 	initialPhase: WorkflowPhase;
102 | 	transitions: StateTransition[];
103 | }
104 | 
105 | /**
106 |  * Workflow event listener
107 |  */
108 | export type WorkflowEventListener = (event: WorkflowEventData) => void;
109 | 
110 | /**
111 |  * Comprehensive event data for workflow events
112 |  */
113 | export interface WorkflowEventData {
114 | 	type: WorkflowEventType;
115 | 	timestamp: Date;
116 | 	phase: WorkflowPhase;
117 | 	tddPhase?: TDDPhase;
118 | 	subtaskId?: string;
119 | 	data?: Record<string, unknown>;
120 | }
121 | 
122 | /**
123 |  * All possible workflow event types
124 |  */
125 | export type WorkflowEventType =
126 | 	| 'workflow:started'
127 | 	| 'workflow:completed'
128 | 	| 'workflow:error'
129 | 	| 'workflow:resumed'
130 | 	| 'phase:entered'
131 | 	| 'phase:exited'
132 | 	| 'tdd:feature-already-implemented'
133 | 	| 'tdd:red:started'
134 | 	| 'tdd:red:completed'
135 | 	| 'tdd:green:started'
136 | 	| 'tdd:green:completed'
137 | 	| 'tdd:commit:started'
138 | 	| 'tdd:commit:completed'
139 | 	| 'subtask:started'
140 | 	| 'subtask:completed'
141 | 	| 'subtask:failed'
142 | 	| 'test:run'
143 | 	| 'test:passed'
144 | 	| 'test:failed'
145 | 	| 'git:branch:created'
146 | 	| 'git:commit:created'
147 | 	| 'error:occurred'
148 | 	| 'state:persisted'
149 | 	| 'progress:updated'
150 | 	| 'adapter:configured';
151 | 
```

--------------------------------------------------------------------------------
/.github/workflows/extension-release.yml:
--------------------------------------------------------------------------------

```yaml
  1 | name: Extension Release
  2 | 
  3 | on:
  4 |   push:
  5 |     tags:
  6 |       - "extension@*"
  7 | 
  8 | permissions:
  9 |   contents: write
 10 | 
 11 | concurrency: extension-release-${{ github.ref }}
 12 | 
 13 | jobs:
 14 |   publish-extension:
 15 |     runs-on: ubuntu-latest
 16 |     environment: extension-release
 17 |     steps:
 18 |       - uses: actions/checkout@v4
 19 | 
 20 |       - uses: actions/setup-node@v4
 21 |         with:
 22 |           node-version: 20
 23 | 
 24 |       - name: Cache node_modules
 25 |         uses: actions/cache@v4
 26 |         with:
 27 |           path: |
 28 |             node_modules
 29 |             */*/node_modules
 30 |           key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
 31 |           restore-keys: |
 32 |             ${{ runner.os }}-node-
 33 | 
 34 |       - name: Install Monorepo Dependencies
 35 |         run: npm ci
 36 |         timeout-minutes: 5
 37 | 
 38 |       - name: Type Check Extension
 39 |         working-directory: apps/extension
 40 |         run: npm run typecheck
 41 |         env:
 42 |           FORCE_COLOR: 1
 43 | 
 44 |       - name: Build Extension
 45 |         working-directory: apps/extension
 46 |         run: npm run build
 47 |         env:
 48 |           FORCE_COLOR: 1
 49 | 
 50 |       - name: Package Extension
 51 |         working-directory: apps/extension
 52 |         run: npm run package
 53 |         env:
 54 |           FORCE_COLOR: 1
 55 | 
 56 |       - name: Create VSIX Package
 57 |         working-directory: apps/extension/vsix-build
 58 |         run: npx vsce package --no-dependencies
 59 |         env:
 60 |           FORCE_COLOR: 1
 61 | 
 62 |       - name: Get VSIX filename
 63 |         id: vsix-info
 64 |         working-directory: apps/extension/vsix-build
 65 |         run: |
 66 |           VSIX_FILE=$(find . -maxdepth 1 -name "*.vsix" -type f | head -n1 | xargs basename)
 67 |           if [ -z "$VSIX_FILE" ]; then
 68 |             echo "Error: No VSIX file found"
 69 |             exit 1
 70 |           fi
 71 |           echo "vsix-filename=$VSIX_FILE" >> "$GITHUB_OUTPUT"
 72 |           echo "Found VSIX: $VSIX_FILE"
 73 | 
 74 |       - name: Publish to VS Code Marketplace
 75 |         working-directory: apps/extension/vsix-build
 76 |         run: npx vsce publish --packagePath "${{ steps.vsix-info.outputs.vsix-filename }}"
 77 |         env:
 78 |           VSCE_PAT: ${{ secrets.VSCE_PAT }}
 79 |           FORCE_COLOR: 1
 80 | 
 81 |       - name: Install Open VSX CLI
 82 |         run: npm install -g ovsx
 83 | 
 84 |       - name: Publish to Open VSX Registry
 85 |         working-directory: apps/extension/vsix-build
 86 |         run: ovsx publish "${{ steps.vsix-info.outputs.vsix-filename }}"
 87 |         env:
 88 |           OVSX_PAT: ${{ secrets.OVSX_PAT }}
 89 |           FORCE_COLOR: 1
 90 | 
 91 |       - name: Upload Build Artifacts
 92 |         uses: actions/upload-artifact@v4
 93 |         with:
 94 |           name: extension-release-${{ github.ref_name }}
 95 |           path: |
 96 |             apps/extension/vsix-build/*.vsix
 97 |             apps/extension/dist/
 98 |           retention-days: 90
 99 | 
100 |   notify-success:
101 |     needs: publish-extension
102 |     if: success()
103 |     runs-on: ubuntu-latest
104 |     steps:
105 |       - name: Success Notification
106 |         run: |
107 |           echo "🎉 Extension ${{ github.ref_name }} successfully published!"
108 |           echo "📦 Available on VS Code Marketplace"
109 |           echo "🌍 Available on Open VSX Registry"
110 |           echo "🏷️ GitHub release created: ${{ github.ref_name }}"
111 | 
```

--------------------------------------------------------------------------------
/apps/cli/src/commands/autopilot/status.command.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview Status Command - Show workflow progress
  3 |  */
  4 | 
  5 | import { WorkflowOrchestrator } from '@tm/core';
  6 | import { Command } from 'commander';
  7 | import {
  8 | 	AutopilotBaseOptions,
  9 | 	OutputFormatter,
 10 | 	hasWorkflowState,
 11 | 	loadWorkflowState
 12 | } from './shared.js';
 13 | import { getProjectRoot } from '../../utils/project-root.js';
 14 | 
 15 | type StatusOptions = AutopilotBaseOptions;
 16 | 
 17 | /**
 18 |  * Status Command - Show current workflow status
 19 |  */
 20 | export class StatusCommand extends Command {
 21 | 	constructor() {
 22 | 		super('status');
 23 | 
 24 | 		this.description('Show current TDD workflow status and progress').action(
 25 | 			async (options: StatusOptions) => {
 26 | 				await this.execute(options);
 27 | 			}
 28 | 		);
 29 | 	}
 30 | 
 31 | 	private async execute(options: StatusOptions): Promise<void> {
 32 | 		// Inherit parent options
 33 | 		const parentOpts = this.parent?.opts() as AutopilotBaseOptions;
 34 | 		const mergedOptions: StatusOptions = {
 35 | 			...parentOpts,
 36 | 			...options,
 37 | 			projectRoot: getProjectRoot(
 38 | 				options.projectRoot || parentOpts?.projectRoot
 39 | 			)
 40 | 		};
 41 | 
 42 | 		const formatter = new OutputFormatter(mergedOptions.json || false);
 43 | 
 44 | 		try {
 45 | 			// Check for workflow state
 46 | 			const hasState = await hasWorkflowState(mergedOptions.projectRoot!);
 47 | 			if (!hasState) {
 48 | 				formatter.error('No active workflow', {
 49 | 					suggestion: 'Start a workflow with: autopilot start <taskId>'
 50 | 				});
 51 | 				process.exit(1);
 52 | 			}
 53 | 
 54 | 			// Load state
 55 | 			const state = await loadWorkflowState(mergedOptions.projectRoot!);
 56 | 			if (!state) {
 57 | 				formatter.error('Failed to load workflow state');
 58 | 				process.exit(1);
 59 | 			}
 60 | 
 61 | 			// Restore orchestrator
 62 | 			const orchestrator = new WorkflowOrchestrator(state.context);
 63 | 			orchestrator.restoreState(state);
 64 | 
 65 | 			// Get status information
 66 | 			const phase = orchestrator.getCurrentPhase();
 67 | 			const tddPhase = orchestrator.getCurrentTDDPhase();
 68 | 			const progress = orchestrator.getProgress();
 69 | 			const currentSubtask = orchestrator.getCurrentSubtask();
 70 | 			const errors = state.context.errors ?? [];
 71 | 
 72 | 			// Build status output
 73 | 			const status = {
 74 | 				taskId: state.context.taskId,
 75 | 				phase,
 76 | 				tddPhase,
 77 | 				branchName: state.context.branchName,
 78 | 				progress: {
 79 | 					completed: progress.completed,
 80 | 					total: progress.total,
 81 | 					current: progress.current,
 82 | 					percentage: progress.percentage
 83 | 				},
 84 | 				currentSubtask: currentSubtask
 85 | 					? {
 86 | 							id: currentSubtask.id,
 87 | 							title: currentSubtask.title,
 88 | 							status: currentSubtask.status,
 89 | 							attempts: currentSubtask.attempts,
 90 | 							maxAttempts: currentSubtask.maxAttempts
 91 | 						}
 92 | 					: null,
 93 | 				subtasks: state.context.subtasks.map((st) => ({
 94 | 					id: st.id,
 95 | 					title: st.title,
 96 | 					status: st.status,
 97 | 					attempts: st.attempts
 98 | 				})),
 99 | 				errors: errors.length > 0 ? errors : undefined,
100 | 				metadata: state.context.metadata
101 | 			};
102 | 
103 | 			if (mergedOptions.json) {
104 | 				formatter.output(status);
105 | 			} else {
106 | 				formatter.success('Workflow status', status);
107 | 			}
108 | 		} catch (error) {
109 | 			formatter.error((error as Error).message);
110 | 			if (mergedOptions.verbose) {
111 | 				console.error((error as Error).stack);
112 | 			}
113 | 			process.exit(1);
114 | 		}
115 | 	}
116 | }
117 | 
```

--------------------------------------------------------------------------------
/apps/cli/src/commands/autopilot/resume.command.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview Resume Command - Restore and resume TDD workflow
  3 |  */
  4 | 
  5 | import { WorkflowOrchestrator } from '@tm/core';
  6 | import { Command } from 'commander';
  7 | import {
  8 | 	AutopilotBaseOptions,
  9 | 	OutputFormatter,
 10 | 	hasWorkflowState,
 11 | 	loadWorkflowState
 12 | } from './shared.js';
 13 | import { getProjectRoot } from '../../utils/project-root.js';
 14 | 
 15 | type ResumeOptions = AutopilotBaseOptions;
 16 | 
 17 | /**
 18 |  * Resume Command - Restore workflow from saved state
 19 |  */
 20 | export class ResumeCommand extends Command {
 21 | 	constructor() {
 22 | 		super('resume');
 23 | 
 24 | 		this.description('Resume a previously started TDD workflow').action(
 25 | 			async (options: ResumeOptions) => {
 26 | 				await this.execute(options);
 27 | 			}
 28 | 		);
 29 | 	}
 30 | 
 31 | 	private async execute(options: ResumeOptions): Promise<void> {
 32 | 		// Inherit parent options (autopilot command)
 33 | 		const parentOpts = this.parent?.opts() as AutopilotBaseOptions;
 34 | 		const mergedOptions: ResumeOptions = {
 35 | 			...parentOpts,
 36 | 			...options,
 37 | 			projectRoot: getProjectRoot(
 38 | 				options.projectRoot || parentOpts?.projectRoot
 39 | 			)
 40 | 		};
 41 | 
 42 | 		const formatter = new OutputFormatter(mergedOptions.json || false);
 43 | 
 44 | 		try {
 45 | 			// Check for workflow state
 46 | 			const hasState = await hasWorkflowState(mergedOptions.projectRoot!);
 47 | 			if (!hasState) {
 48 | 				formatter.error('No workflow state found', {
 49 | 					suggestion: 'Start a new workflow with: autopilot start <taskId>'
 50 | 				});
 51 | 				process.exit(1);
 52 | 			}
 53 | 
 54 | 			// Load state
 55 | 			formatter.info('Loading workflow state...');
 56 | 			const state = await loadWorkflowState(mergedOptions.projectRoot!);
 57 | 
 58 | 			if (!state) {
 59 | 				formatter.error('Failed to load workflow state');
 60 | 				process.exit(1);
 61 | 			}
 62 | 
 63 | 			// Validate state can be resumed
 64 | 			const orchestrator = new WorkflowOrchestrator(state.context);
 65 | 			if (!orchestrator.canResumeFromState(state)) {
 66 | 				formatter.error('Invalid workflow state', {
 67 | 					suggestion:
 68 | 						'State file may be corrupted. Consider starting a new workflow.'
 69 | 				});
 70 | 				process.exit(1);
 71 | 			}
 72 | 
 73 | 			// Restore state
 74 | 			orchestrator.restoreState(state);
 75 | 
 76 | 			// Re-enable auto-persistence
 77 | 			const { saveWorkflowState } = await import('./shared.js');
 78 | 			orchestrator.enableAutoPersist(async (newState) => {
 79 | 				await saveWorkflowState(mergedOptions.projectRoot!, newState);
 80 | 			});
 81 | 
 82 | 			// Get progress
 83 | 			const progress = orchestrator.getProgress();
 84 | 			const currentSubtask = orchestrator.getCurrentSubtask();
 85 | 
 86 | 			// Output success
 87 | 			formatter.success('Workflow resumed', {
 88 | 				taskId: state.context.taskId,
 89 | 				phase: orchestrator.getCurrentPhase(),
 90 | 				tddPhase: orchestrator.getCurrentTDDPhase(),
 91 | 				branchName: state.context.branchName,
 92 | 				progress: {
 93 | 					completed: progress.completed,
 94 | 					total: progress.total,
 95 | 					percentage: progress.percentage
 96 | 				},
 97 | 				currentSubtask: currentSubtask
 98 | 					? {
 99 | 							id: currentSubtask.id,
100 | 							title: currentSubtask.title,
101 | 							attempts: currentSubtask.attempts
102 | 						}
103 | 					: null
104 | 			});
105 | 		} catch (error) {
106 | 			formatter.error((error as Error).message);
107 | 			if (mergedOptions.verbose) {
108 | 				console.error((error as Error).stack);
109 | 			}
110 | 			process.exit(1);
111 | 		}
112 | 	}
113 | }
114 | 
```

--------------------------------------------------------------------------------
/tests/integration/providers/temperature-support.test.js:
--------------------------------------------------------------------------------

```javascript
 1 | /**
 2 |  * Integration Tests for Provider Temperature Support
 3 |  *
 4 |  * This test suite verifies that all providers correctly declare their
 5 |  * temperature support capabilities. CLI providers should have
 6 |  * supportsTemperature = false, while standard API providers should
 7 |  * have supportsTemperature = true.
 8 |  *
 9 |  * These tests are separated from unit tests to avoid coupling
10 |  * base provider tests with concrete provider implementations.
11 |  */
12 | 
13 | import { ClaudeCodeProvider } from '../../../src/ai-providers/claude-code.js';
14 | import { CodexCliProvider } from '../../../src/ai-providers/codex-cli.js';
15 | import { GeminiCliProvider } from '../../../src/ai-providers/gemini-cli.js';
16 | import { GrokCliProvider } from '../../../src/ai-providers/grok-cli.js';
17 | import { AnthropicAIProvider } from '../../../src/ai-providers/anthropic.js';
18 | import { OpenAIProvider } from '../../../src/ai-providers/openai.js';
19 | import { GoogleAIProvider } from '../../../src/ai-providers/google.js';
20 | import { PerplexityAIProvider } from '../../../src/ai-providers/perplexity.js';
21 | import { XAIProvider } from '../../../src/ai-providers/xai.js';
22 | import { GroqProvider } from '../../../src/ai-providers/groq.js';
23 | import { OpenRouterAIProvider } from '../../../src/ai-providers/openrouter.js';
24 | import { OllamaAIProvider } from '../../../src/ai-providers/ollama.js';
25 | import { BedrockAIProvider } from '../../../src/ai-providers/bedrock.js';
26 | import { AzureProvider } from '../../../src/ai-providers/azure.js';
27 | import { VertexAIProvider } from '../../../src/ai-providers/google-vertex.js';
28 | 
29 | describe('Provider Temperature Support', () => {
30 | 	describe('CLI Providers', () => {
31 | 		it('should verify CLI providers have supportsTemperature = false', () => {
32 | 			expect(new ClaudeCodeProvider().supportsTemperature).toBe(false);
33 | 			expect(new CodexCliProvider().supportsTemperature).toBe(false);
34 | 			expect(new GeminiCliProvider().supportsTemperature).toBe(false);
35 | 			expect(new GrokCliProvider().supportsTemperature).toBe(false);
36 | 		});
37 | 	});
38 | 
39 | 	describe('Standard API Providers', () => {
40 | 		it('should verify standard providers have supportsTemperature = true', () => {
41 | 			expect(new AnthropicAIProvider().supportsTemperature).toBe(true);
42 | 			expect(new OpenAIProvider().supportsTemperature).toBe(true);
43 | 			expect(new GoogleAIProvider().supportsTemperature).toBe(true);
44 | 			expect(new PerplexityAIProvider().supportsTemperature).toBe(true);
45 | 			expect(new XAIProvider().supportsTemperature).toBe(true);
46 | 			expect(new GroqProvider().supportsTemperature).toBe(true);
47 | 			expect(new OpenRouterAIProvider().supportsTemperature).toBe(true);
48 | 		});
49 | 	});
50 | 
51 | 	describe('Special Case Providers', () => {
52 | 		it('should verify Ollama provider has supportsTemperature = true', () => {
53 | 			expect(new OllamaAIProvider().supportsTemperature).toBe(true);
54 | 		});
55 | 
56 | 		it('should verify cloud providers have supportsTemperature = true', () => {
57 | 			expect(new BedrockAIProvider().supportsTemperature).toBe(true);
58 | 			expect(new AzureProvider().supportsTemperature).toBe(true);
59 | 			expect(new VertexAIProvider().supportsTemperature).toBe(true);
60 | 		});
61 | 	});
62 | });
63 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/tools/update-task.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * tools/update-task.js
  3 |  * Tool to update a single task by ID with new information
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	handleApiResult,
  9 | 	createErrorResponse,
 10 | 	withNormalizedProjectRoot
 11 | } from './utils.js';
 12 | import { updateTaskByIdDirect } from '../core/task-master-core.js';
 13 | import { findTasksPath } from '../core/utils/path-utils.js';
 14 | import { resolveTag } from '../../../scripts/modules/utils.js';
 15 | 
 16 | /**
 17 |  * Register the update-task tool with the MCP server
 18 |  * @param {Object} server - FastMCP server instance
 19 |  */
 20 | export function registerUpdateTaskTool(server) {
 21 | 	server.addTool({
 22 | 		name: 'update_task',
 23 | 		description:
 24 | 			'Updates a single task by ID with new information or context provided in the prompt.',
 25 | 		parameters: z.object({
 26 | 			id: z
 27 | 				.string() // ID can be number or string like "1.2"
 28 | 				.describe(
 29 | 					"ID of the task (e.g., '15') to update. Subtasks are supported using the update-subtask tool."
 30 | 				),
 31 | 			prompt: z
 32 | 				.string()
 33 | 				.describe('New information or context to incorporate into the task'),
 34 | 			research: z
 35 | 				.boolean()
 36 | 				.optional()
 37 | 				.describe('Use Perplexity AI for research-backed updates'),
 38 | 			append: z
 39 | 				.boolean()
 40 | 				.optional()
 41 | 				.describe(
 42 | 					'Append timestamped information to task details instead of full update'
 43 | 				),
 44 | 			file: z.string().optional().describe('Absolute path to the tasks file'),
 45 | 			projectRoot: z
 46 | 				.string()
 47 | 				.describe('The directory of the project. Must be an absolute path.'),
 48 | 			tag: z.string().optional().describe('Tag context to operate on')
 49 | 		}),
 50 | 		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
 51 | 			const toolName = 'update_task';
 52 | 			try {
 53 | 				const resolvedTag = resolveTag({
 54 | 					projectRoot: args.projectRoot,
 55 | 					tag: args.tag
 56 | 				});
 57 | 				log.info(
 58 | 					`Executing ${toolName} tool with args: ${JSON.stringify(args)}`
 59 | 				);
 60 | 
 61 | 				let tasksJsonPath;
 62 | 				try {
 63 | 					tasksJsonPath = findTasksPath(
 64 | 						{ projectRoot: args.projectRoot, file: args.file },
 65 | 						log
 66 | 					);
 67 | 					log.info(`${toolName}: Resolved tasks path: ${tasksJsonPath}`);
 68 | 				} catch (error) {
 69 | 					log.error(`${toolName}: Error finding tasks.json: ${error.message}`);
 70 | 					return createErrorResponse(
 71 | 						`Failed to find tasks.json: ${error.message}`
 72 | 					);
 73 | 				}
 74 | 
 75 | 				// 3. Call Direct Function - Include projectRoot
 76 | 				const result = await updateTaskByIdDirect(
 77 | 					{
 78 | 						tasksJsonPath: tasksJsonPath,
 79 | 						id: args.id,
 80 | 						prompt: args.prompt,
 81 | 						research: args.research,
 82 | 						append: args.append,
 83 | 						projectRoot: args.projectRoot,
 84 | 						tag: resolvedTag
 85 | 					},
 86 | 					log,
 87 | 					{ session }
 88 | 				);
 89 | 
 90 | 				// 4. Handle Result
 91 | 				log.info(
 92 | 					`${toolName}: Direct function result: success=${result.success}`
 93 | 				);
 94 | 				return handleApiResult(
 95 | 					result,
 96 | 					log,
 97 | 					'Error updating task',
 98 | 					undefined,
 99 | 					args.projectRoot
100 | 				);
101 | 			} catch (error) {
102 | 				log.error(
103 | 					`Critical error in ${toolName} tool execute: ${error.message}`
104 | 				);
105 | 				return createErrorResponse(
106 | 					`Internal tool error (${toolName}): ${error.message}`
107 | 				);
108 | 			}
109 | 		})
110 | 	});
111 | }
112 | 
```

--------------------------------------------------------------------------------
/src/prompts/schemas/prompt-template.schema.json:
--------------------------------------------------------------------------------

```json
  1 | {
  2 | 	"$schema": "http://json-schema.org/draft-07/schema#",
  3 | 	"$id": "https://github.com/eyaltoledano/claude-task-master/blob/main/src/prompts/schemas/prompt-template.schema.json",
  4 | 	"version": "1.0.0",
  5 | 	"title": "Task Master Prompt Template",
  6 | 	"description": "Schema for Task Master AI prompt template files",
  7 | 	"type": "object",
  8 | 	"required": ["id", "version", "description", "prompts"],
  9 | 	"properties": {
 10 | 		"id": {
 11 | 			"type": "string",
 12 | 			"pattern": "^[a-z0-9-]+$",
 13 | 			"description": "Unique identifier for the prompt template"
 14 | 		},
 15 | 		"version": {
 16 | 			"type": "string",
 17 | 			"pattern": "^\\d+\\.\\d+\\.\\d+$",
 18 | 			"description": "Semantic version of the prompt template"
 19 | 		},
 20 | 		"description": {
 21 | 			"type": "string",
 22 | 			"minLength": 1,
 23 | 			"description": "Brief description of what this prompt does"
 24 | 		},
 25 | 		"metadata": {
 26 | 			"$ref": "#/definitions/metadata"
 27 | 		},
 28 | 		"parameters": {
 29 | 			"type": "object",
 30 | 			"additionalProperties": {
 31 | 				"$ref": "#/definitions/parameter"
 32 | 			}
 33 | 		},
 34 | 		"prompts": {
 35 | 			"type": "object",
 36 | 			"properties": {
 37 | 				"default": {
 38 | 					"$ref": "#/definitions/promptVariant"
 39 | 				}
 40 | 			},
 41 | 			"additionalProperties": {
 42 | 				"$ref": "#/definitions/conditionalPromptVariant"
 43 | 			}
 44 | 		}
 45 | 	},
 46 | 	"definitions": {
 47 | 		"parameter": {
 48 | 			"type": "object",
 49 | 			"required": ["type", "description"],
 50 | 			"properties": {
 51 | 				"type": {
 52 | 					"type": "string",
 53 | 					"enum": ["string", "number", "boolean", "array", "object"]
 54 | 				},
 55 | 				"description": {
 56 | 					"type": "string",
 57 | 					"minLength": 1
 58 | 				},
 59 | 				"required": {
 60 | 					"type": "boolean",
 61 | 					"default": false
 62 | 				},
 63 | 				"default": {
 64 | 					"description": "Default value for optional parameters"
 65 | 				},
 66 | 				"enum": {
 67 | 					"type": "array",
 68 | 					"description": "Valid values for string parameters"
 69 | 				},
 70 | 				"pattern": {
 71 | 					"type": "string",
 72 | 					"description": "Regular expression pattern for string validation"
 73 | 				},
 74 | 				"minimum": {
 75 | 					"type": "number",
 76 | 					"description": "Minimum value for number parameters"
 77 | 				},
 78 | 				"maximum": {
 79 | 					"type": "number",
 80 | 					"description": "Maximum value for number parameters"
 81 | 				}
 82 | 			}
 83 | 		},
 84 | 		"promptVariant": {
 85 | 			"type": "object",
 86 | 			"required": ["system", "user"],
 87 | 			"properties": {
 88 | 				"system": {
 89 | 					"type": "string",
 90 | 					"minLength": 1
 91 | 				},
 92 | 				"user": {
 93 | 					"type": "string",
 94 | 					"minLength": 1
 95 | 				}
 96 | 			}
 97 | 		},
 98 | 		"conditionalPromptVariant": {
 99 | 			"allOf": [
100 | 				{ "$ref": "#/definitions/promptVariant" },
101 | 				{
102 | 					"type": "object",
103 | 					"properties": {
104 | 						"condition": {
105 | 							"type": "string",
106 | 							"description": "JavaScript expression for variant selection"
107 | 						}
108 | 					}
109 | 				}
110 | 			]
111 | 		},
112 | 		"metadata": {
113 | 			"type": "object",
114 | 			"properties": {
115 | 				"author": { "type": "string" },
116 | 				"created": { "type": "string", "format": "date-time" },
117 | 				"updated": { "type": "string", "format": "date-time" },
118 | 				"tags": {
119 | 					"type": "array",
120 | 					"items": { "type": "string" }
121 | 				},
122 | 				"category": {
123 | 					"type": "string",
124 | 					"enum": [
125 | 						"task",
126 | 						"analysis",
127 | 						"research",
128 | 						"parsing",
129 | 						"update",
130 | 						"expansion"
131 | 					]
132 | 				}
133 | 			}
134 | 		}
135 | 	}
136 | }
137 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/generate-task-files.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * generate-task-files.js
  3 |  * Direct function implementation for generating task files from tasks.json
  4 |  */
  5 | 
  6 | import { generateTaskFiles } from '../../../../scripts/modules/task-manager.js';
  7 | import {
  8 | 	enableSilentMode,
  9 | 	disableSilentMode
 10 | } from '../../../../scripts/modules/utils.js';
 11 | 
 12 | /**
 13 |  * Direct function wrapper for generateTaskFiles with error handling.
 14 |  *
 15 |  * @param {Object} args - Command arguments containing tasksJsonPath and outputDir.
 16 |  * @param {string} args.tasksJsonPath - Path to the tasks.json file.
 17 |  * @param {string} args.outputDir - Path to the output directory.
 18 |  * @param {string} args.projectRoot - Project root path (for MCP/env fallback)
 19 |  * @param {string} args.tag - Tag for the task (optional)
 20 |  * @param {Object} log - Logger object.
 21 |  * @returns {Promise<Object>} - Result object with success status and data/error information.
 22 |  */
 23 | export async function generateTaskFilesDirect(args, log) {
 24 | 	// Destructure expected args
 25 | 	const { tasksJsonPath, outputDir, projectRoot, tag } = args;
 26 | 	try {
 27 | 		log.info(`Generating task files with args: ${JSON.stringify(args)}`);
 28 | 
 29 | 		// Check if paths were provided
 30 | 		if (!tasksJsonPath) {
 31 | 			const errorMessage = 'tasksJsonPath is required but was not provided.';
 32 | 			log.error(errorMessage);
 33 | 			return {
 34 | 				success: false,
 35 | 				error: { code: 'MISSING_ARGUMENT', message: errorMessage }
 36 | 			};
 37 | 		}
 38 | 		if (!outputDir) {
 39 | 			const errorMessage = 'outputDir is required but was not provided.';
 40 | 			log.error(errorMessage);
 41 | 			return {
 42 | 				success: false,
 43 | 				error: { code: 'MISSING_ARGUMENT', message: errorMessage }
 44 | 			};
 45 | 		}
 46 | 
 47 | 		// Use the provided paths
 48 | 		const tasksPath = tasksJsonPath;
 49 | 		const resolvedOutputDir = outputDir;
 50 | 
 51 | 		log.info(`Generating task files from ${tasksPath} to ${resolvedOutputDir}`);
 52 | 
 53 | 		// Execute core generateTaskFiles function in a separate try/catch
 54 | 		try {
 55 | 			// Enable silent mode to prevent logs from being written to stdout
 56 | 			enableSilentMode();
 57 | 
 58 | 			// Pass projectRoot and tag so the core respects context
 59 | 			generateTaskFiles(tasksPath, resolvedOutputDir, {
 60 | 				projectRoot,
 61 | 				tag,
 62 | 				mcpLog: log
 63 | 			});
 64 | 
 65 | 			// Restore normal logging after task generation
 66 | 			disableSilentMode();
 67 | 		} catch (genError) {
 68 | 			// Make sure to restore normal logging even if there's an error
 69 | 			disableSilentMode();
 70 | 
 71 | 			log.error(`Error in generateTaskFiles: ${genError.message}`);
 72 | 			return {
 73 | 				success: false,
 74 | 				error: { code: 'GENERATE_FILES_ERROR', message: genError.message }
 75 | 			};
 76 | 		}
 77 | 
 78 | 		// Return success with file paths
 79 | 		return {
 80 | 			success: true,
 81 | 			data: {
 82 | 				message: `Successfully generated task files`,
 83 | 				tasksPath: tasksPath,
 84 | 				outputDir: resolvedOutputDir,
 85 | 				taskFiles:
 86 | 					'Individual task files have been generated in the output directory'
 87 | 			}
 88 | 		};
 89 | 	} catch (error) {
 90 | 		// Make sure to restore normal logging if an outer error occurs
 91 | 		disableSilentMode();
 92 | 
 93 | 		log.error(`Error generating task files: ${error.message}`);
 94 | 		return {
 95 | 			success: false,
 96 | 			error: {
 97 | 				code: 'GENERATE_TASKS_ERROR',
 98 | 				message: error.message || 'Unknown error generating task files'
 99 | 			}
100 | 		};
101 | 	}
102 | }
103 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/tools/models.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * models.js
  3 |  * MCP tool for managing AI model configurations
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	handleApiResult,
  9 | 	createErrorResponse,
 10 | 	withNormalizedProjectRoot
 11 | } from './utils.js';
 12 | import { modelsDirect } from '../core/task-master-core.js';
 13 | 
 14 | /**
 15 |  * Register the models tool with the MCP server
 16 |  * @param {Object} server - FastMCP server instance
 17 |  */
 18 | export function registerModelsTool(server) {
 19 | 	server.addTool({
 20 | 		name: 'models',
 21 | 		description:
 22 | 			'Get information about available AI models or set model configurations. Run without arguments to get the current model configuration and API key status for the selected model providers.',
 23 | 		parameters: z.object({
 24 | 			setMain: z
 25 | 				.string()
 26 | 				.optional()
 27 | 				.describe(
 28 | 					'Set the primary model for task generation/updates. Model provider API key is required in the MCP config ENV.'
 29 | 				),
 30 | 			setResearch: z
 31 | 				.string()
 32 | 				.optional()
 33 | 				.describe(
 34 | 					'Set the model for research-backed operations. Model provider API key is required in the MCP config ENV.'
 35 | 				),
 36 | 			setFallback: z
 37 | 				.string()
 38 | 				.optional()
 39 | 				.describe(
 40 | 					'Set the model to use if the primary fails. Model provider API key is required in the MCP config ENV.'
 41 | 				),
 42 | 			listAvailableModels: z
 43 | 				.boolean()
 44 | 				.optional()
 45 | 				.describe(
 46 | 					'List all available models not currently in use. Input/output costs values are in dollars (3 is $3.00).'
 47 | 				),
 48 | 			projectRoot: z
 49 | 				.string()
 50 | 				.describe('The directory of the project. Must be an absolute path.'),
 51 | 			openrouter: z
 52 | 				.boolean()
 53 | 				.optional()
 54 | 				.describe('Indicates the set model ID is a custom OpenRouter model.'),
 55 | 			ollama: z
 56 | 				.boolean()
 57 | 				.optional()
 58 | 				.describe('Indicates the set model ID is a custom Ollama model.'),
 59 | 			bedrock: z
 60 | 				.boolean()
 61 | 				.optional()
 62 | 				.describe('Indicates the set model ID is a custom AWS Bedrock model.'),
 63 | 			azure: z
 64 | 				.boolean()
 65 | 				.optional()
 66 | 				.describe('Indicates the set model ID is a custom Azure OpenAI model.'),
 67 | 			vertex: z
 68 | 				.boolean()
 69 | 				.optional()
 70 | 				.describe(
 71 | 					'Indicates the set model ID is a custom Google Vertex AI model.'
 72 | 				),
 73 | 			'openai-compatible': z
 74 | 				.boolean()
 75 | 				.optional()
 76 | 				.describe(
 77 | 					'Indicates the set model ID is a custom OpenAI-compatible model. Requires baseURL parameter.'
 78 | 				),
 79 | 			baseURL: z
 80 | 				.string()
 81 | 				.optional()
 82 | 				.describe(
 83 | 					'Custom base URL for providers that support it (e.g., https://api.example.com/v1).'
 84 | 				)
 85 | 		}),
 86 | 		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
 87 | 			try {
 88 | 				log.info(`Starting models tool with args: ${JSON.stringify(args)}`);
 89 | 
 90 | 				// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
 91 | 				const result = await modelsDirect(
 92 | 					{ ...args, projectRoot: args.projectRoot },
 93 | 					log,
 94 | 					{ session }
 95 | 				);
 96 | 
 97 | 				return handleApiResult(
 98 | 					result,
 99 | 					log,
100 | 					'Error managing models',
101 | 					undefined,
102 | 					args.projectRoot
103 | 				);
104 | 			} catch (error) {
105 | 				log.error(`Error in models tool: ${error.message}`);
106 | 				return createErrorResponse(error.message);
107 | 			}
108 | 		})
109 | 	});
110 | }
111 | 
```

--------------------------------------------------------------------------------
/tests/unit/mcp/tools/__mocks__/move-task.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Mock for move-task module
  3 |  * Provides mock implementations for testing scenarios
  4 |  */
  5 | 
  6 | // Mock the moveTask function from the core module
  7 | const mockMoveTask = jest
  8 | 	.fn()
  9 | 	.mockImplementation(
 10 | 		async (tasksPath, sourceId, destinationId, generateFiles, options) => {
 11 | 			// Simulate successful move operation
 12 | 			return {
 13 | 				success: true,
 14 | 				sourceId,
 15 | 				destinationId,
 16 | 				message: `Successfully moved task ${sourceId} to ${destinationId}`,
 17 | 				...options
 18 | 			};
 19 | 		}
 20 | 	);
 21 | 
 22 | // Mock the moveTaskDirect function
 23 | const mockMoveTaskDirect = jest
 24 | 	.fn()
 25 | 	.mockImplementation(async (args, log, context = {}) => {
 26 | 		// Validate required parameters
 27 | 		if (!args.sourceId) {
 28 | 			return {
 29 | 				success: false,
 30 | 				error: {
 31 | 					message: 'Source ID is required',
 32 | 					code: 'MISSING_SOURCE_ID'
 33 | 				}
 34 | 			};
 35 | 		}
 36 | 
 37 | 		if (!args.destinationId) {
 38 | 			return {
 39 | 				success: false,
 40 | 				error: {
 41 | 					message: 'Destination ID is required',
 42 | 					code: 'MISSING_DESTINATION_ID'
 43 | 				}
 44 | 			};
 45 | 		}
 46 | 
 47 | 		// Simulate successful move
 48 | 		return {
 49 | 			success: true,
 50 | 			data: {
 51 | 				sourceId: args.sourceId,
 52 | 				destinationId: args.destinationId,
 53 | 				message: `Successfully moved task/subtask ${args.sourceId} to ${args.destinationId}`,
 54 | 				tag: args.tag,
 55 | 				projectRoot: args.projectRoot
 56 | 			}
 57 | 		};
 58 | 	});
 59 | 
 60 | // Mock the moveTaskCrossTagDirect function
 61 | const mockMoveTaskCrossTagDirect = jest
 62 | 	.fn()
 63 | 	.mockImplementation(async (args, log, context = {}) => {
 64 | 		// Validate required parameters
 65 | 		if (!args.sourceIds) {
 66 | 			return {
 67 | 				success: false,
 68 | 				error: {
 69 | 					message: 'Source IDs are required',
 70 | 					code: 'MISSING_SOURCE_IDS'
 71 | 				}
 72 | 			};
 73 | 		}
 74 | 
 75 | 		if (!args.sourceTag) {
 76 | 			return {
 77 | 				success: false,
 78 | 				error: {
 79 | 					message: 'Source tag is required for cross-tag moves',
 80 | 					code: 'MISSING_SOURCE_TAG'
 81 | 				}
 82 | 			};
 83 | 		}
 84 | 
 85 | 		if (!args.targetTag) {
 86 | 			return {
 87 | 				success: false,
 88 | 				error: {
 89 | 					message: 'Target tag is required for cross-tag moves',
 90 | 					code: 'MISSING_TARGET_TAG'
 91 | 				}
 92 | 			};
 93 | 		}
 94 | 
 95 | 		if (args.sourceTag === args.targetTag) {
 96 | 			return {
 97 | 				success: false,
 98 | 				error: {
 99 | 					message: `Source and target tags are the same ("${args.sourceTag}")`,
100 | 					code: 'SAME_SOURCE_TARGET_TAG'
101 | 				}
102 | 			};
103 | 		}
104 | 
105 | 		// Simulate successful cross-tag move
106 | 		return {
107 | 			success: true,
108 | 			data: {
109 | 				sourceIds: args.sourceIds,
110 | 				sourceTag: args.sourceTag,
111 | 				targetTag: args.targetTag,
112 | 				message: `Successfully moved tasks ${args.sourceIds} from ${args.sourceTag} to ${args.targetTag}`,
113 | 				withDependencies: args.withDependencies || false,
114 | 				ignoreDependencies: args.ignoreDependencies || false
115 | 			}
116 | 		};
117 | 	});
118 | 
119 | // Mock the registerMoveTaskTool function
120 | const mockRegisterMoveTaskTool = jest.fn().mockImplementation((server) => {
121 | 	// Simulate tool registration
122 | 	server.addTool({
123 | 		name: 'move_task',
124 | 		description: 'Move a task or subtask to a new position',
125 | 		parameters: {},
126 | 		execute: jest.fn()
127 | 	});
128 | });
129 | 
130 | // Export the mock functions
131 | export {
132 | 	mockMoveTask,
133 | 	mockMoveTaskDirect,
134 | 	mockMoveTaskCrossTagDirect,
135 | 	mockRegisterMoveTaskTool
136 | };
137 | 
138 | // Default export for the main moveTask function
139 | export default mockMoveTask;
140 | 
```

--------------------------------------------------------------------------------
/assets/GEMINI.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Gemini CLI-Specific Instructions
  2 | 
  3 | > **Note:** This file works alongside `AGENTS.md` (generic AI agent instructions). AGENTS.md contains the core Task Master commands and workflows for all AI agents. This file contains only Gemini CLI-specific features and integrations.
  4 | 
  5 | ## MCP Configuration for Gemini CLI
  6 | 
  7 | Configure Task Master MCP server in `~/.gemini/settings.json`:
  8 | 
  9 | ```json
 10 | {
 11 |   "mcpServers": {
 12 |     "task-master-ai": {
 13 |       "command": "npx",
 14 |       "args": ["-y", "task-master-ai"]
 15 |     }
 16 |   }
 17 | }
 18 | ```
 19 | 
 20 | **Note:** API keys are configured via `task-master models --setup`, not in MCP configuration.
 21 | 
 22 | ## Gemini CLI-Specific Features
 23 | 
 24 | ### Session Management
 25 | 
 26 | Built-in session commands:
 27 | 
 28 | - `/chat` - Start new conversation while keeping context
 29 | - `/checkpoint save <name>` - Save session state
 30 | - `/checkpoint load <name>` - Resume saved session
 31 | - `/memory show` - View loaded context
 32 | 
 33 | Both `AGENTS.md` and `GEMINI.md` are auto-loaded on every Gemini CLI session.
 34 | 
 35 | ### Headless Mode for Automation
 36 | 
 37 | Non-interactive mode for scripts:
 38 | 
 39 | ```bash
 40 | # Simple text response
 41 | gemini -p "What's the next task?"
 42 | 
 43 | # JSON output for parsing
 44 | gemini -p "List all pending tasks" --output-format json
 45 | 
 46 | # Stream events for long operations
 47 | gemini -p "Expand all tasks" --output-format stream-json
 48 | ```
 49 | 
 50 | ### Token Usage Monitoring
 51 | 
 52 | ```bash
 53 | # In Gemini CLI session
 54 | /stats
 55 | 
 56 | # Shows: token usage, API costs, request counts
 57 | ```
 58 | 
 59 | ### Google Search Grounding
 60 | 
 61 | Leverage built-in Google Search as an alternative to Perplexity research mode:
 62 | - Best practices research
 63 | - Library documentation
 64 | - Security vulnerability checks
 65 | - Implementation patterns
 66 | 
 67 | ## Important Differences from Other Agents
 68 | 
 69 | ### No Slash Commands
 70 | Gemini CLI does not support custom slash commands (unlike Claude Code). Use natural language instead.
 71 | 
 72 | ### No Tool Allowlist
 73 | Security is managed at the MCP level, not via agent configuration.
 74 | 
 75 | ### Session Persistence
 76 | Use `/checkpoint` instead of git worktrees for managing multiple work contexts.
 77 | 
 78 | ### Configuration Files
 79 | - Global: `~/.gemini/settings.json`
 80 | - Project: `.gemini/settings.json`
 81 | - **Not**: `.mcp.json` (that's for Claude Code)
 82 | 
 83 | ## Recommended Model Configuration
 84 | 
 85 | For Gemini CLI users:
 86 | 
 87 | ```bash
 88 | # Set Gemini as primary model
 89 | task-master models --set-main gemini-2.0-flash-exp
 90 | task-master models --set-fallback gemini-1.5-flash
 91 | 
 92 | # Optional: Use Perplexity for research (or rely on Google Search)
 93 | task-master models --set-research perplexity-llama-3.1-sonar-large-128k-online
 94 | ```
 95 | 
 96 | ## Your Role with Gemini CLI
 97 | 
 98 | As a Gemini CLI assistant with Task Master:
 99 | 
100 | 1. **Use MCP tools naturally** - They integrate transparently in conversation
101 | 2. **Reference files with @** - Leverage Gemini's file inclusion
102 | 3. **Save checkpoints** - Offer to save state after significant progress
103 | 4. **Monitor usage** - Remind users about `/stats` for long sessions
104 | 5. **Use Google Search** - Leverage search grounding for research
105 | 
106 | **Key Principle:** Focus on natural conversation. Task Master MCP tools work seamlessly with Gemini CLI's interface.
107 | 
108 | ---
109 | 
110 | *See AGENTS.md for complete Task Master commands, workflows, and best practices.*
111 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/tools/parse-prd.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * tools/parsePRD.js
  3 |  * Tool to parse PRD document and generate tasks
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	handleApiResult,
  9 | 	withNormalizedProjectRoot,
 10 | 	createErrorResponse,
 11 | 	checkProgressCapability
 12 | } from './utils.js';
 13 | import { parsePRDDirect } from '../core/task-master-core.js';
 14 | import {
 15 | 	PRD_FILE,
 16 | 	TASKMASTER_DOCS_DIR,
 17 | 	TASKMASTER_TASKS_FILE
 18 | } from '../../../src/constants/paths.js';
 19 | import { resolveTag } from '../../../scripts/modules/utils.js';
 20 | 
 21 | /**
 22 |  * Register the parse_prd tool
 23 |  * @param {Object} server - FastMCP server instance
 24 |  */
 25 | export function registerParsePRDTool(server) {
 26 | 	server.addTool({
 27 | 		name: 'parse_prd',
 28 | 		description: `Parse a Product Requirements Document (PRD) text file to automatically generate initial tasks. Reinitializing the project is not necessary to run this tool. It is recommended to run parse-prd after initializing the project and creating/importing a prd.txt file in the project root's ${TASKMASTER_DOCS_DIR} directory.`,
 29 | 
 30 | 		parameters: z.object({
 31 | 			input: z
 32 | 				.string()
 33 | 				.optional()
 34 | 				.default(PRD_FILE)
 35 | 				.describe('Absolute path to the PRD document file (.txt, .md, etc.)'),
 36 | 			projectRoot: z
 37 | 				.string()
 38 | 				.describe('The directory of the project. Must be an absolute path.'),
 39 | 			tag: z.string().optional().describe('Tag context to operate on'),
 40 | 			output: z
 41 | 				.string()
 42 | 				.optional()
 43 | 				.describe(
 44 | 					`Output path for tasks.json file (default: ${TASKMASTER_TASKS_FILE})`
 45 | 				),
 46 | 			numTasks: z
 47 | 				.string()
 48 | 				.optional()
 49 | 				.describe(
 50 | 					'Approximate number of top-level tasks to generate (default: 10). As the agent, if you have enough information, ensure to enter a number of tasks that would logically scale with project complexity. Setting to 0 will allow Taskmaster to determine the appropriate number of tasks based on the complexity of the PRD. Avoid entering numbers above 50 due to context window limitations.'
 51 | 				),
 52 | 			force: z
 53 | 				.boolean()
 54 | 				.optional()
 55 | 				.default(false)
 56 | 				.describe('Overwrite existing output file without prompting.'),
 57 | 			research: z
 58 | 				.boolean()
 59 | 				.optional()
 60 | 				.describe(
 61 | 					'Enable Taskmaster to use the research role for potentially more informed task generation. Requires appropriate API key.'
 62 | 				),
 63 | 			append: z
 64 | 				.boolean()
 65 | 				.optional()
 66 | 				.describe('Append generated tasks to existing file.')
 67 | 		}),
 68 | 		execute: withNormalizedProjectRoot(
 69 | 			async (args, { log, session, reportProgress }) => {
 70 | 				try {
 71 | 					const resolvedTag = resolveTag({
 72 | 						projectRoot: args.projectRoot,
 73 | 						tag: args.tag
 74 | 					});
 75 | 					const progressCapability = checkProgressCapability(
 76 | 						reportProgress,
 77 | 						log
 78 | 					);
 79 | 					const result = await parsePRDDirect(
 80 | 						{
 81 | 							...args,
 82 | 							tag: resolvedTag
 83 | 						},
 84 | 						log,
 85 | 						{ session, reportProgress: progressCapability }
 86 | 					);
 87 | 					return handleApiResult(
 88 | 						result,
 89 | 						log,
 90 | 						'Error parsing PRD',
 91 | 						undefined,
 92 | 						args.projectRoot
 93 | 					);
 94 | 				} catch (error) {
 95 | 					log.error(`Error in parse_prd: ${error.message}`);
 96 | 					return createErrorResponse(`Failed to parse PRD: ${error.message}`);
 97 | 				}
 98 | 			}
 99 | 		)
100 | 	});
101 | }
102 | 
```

--------------------------------------------------------------------------------
/.github/workflows/pre-release.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Pre-Release (RC)
 2 | 
 3 | on:
 4 |   workflow_dispatch: # Allows manual triggering from GitHub UI/API
 5 | 
 6 | concurrency: pre-release-${{ github.ref_name }}
 7 | jobs:
 8 |   rc:
 9 |     runs-on: ubuntu-latest
10 |     # Only allow pre-releases on non-main branches
11 |     if: github.ref != 'refs/heads/main'
12 |     environment: extension-release
13 |     steps:
14 |       - uses: actions/checkout@v4
15 |         with:
16 |           fetch-depth: 0
17 | 
18 |       - uses: actions/setup-node@v4
19 |         with:
20 |           node-version: 20
21 |           cache: "npm"
22 | 
23 |       - name: Cache node_modules
24 |         uses: actions/cache@v4
25 |         with:
26 |           path: |
27 |             node_modules
28 |             */*/node_modules
29 |           key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
30 |           restore-keys: |
31 |             ${{ runner.os }}-node-
32 | 
33 |       - name: Install dependencies
34 |         run: npm ci
35 |         timeout-minutes: 2
36 | 
37 |       - name: Enter RC mode (if not already in RC mode)
38 |         run: |
39 |           # Check if we're in pre-release mode with the "rc" tag
40 |           if [ -f .changeset/pre.json ]; then
41 |             MODE=$(jq -r '.mode' .changeset/pre.json 2>/dev/null || echo '')
42 |             TAG=$(jq -r '.tag' .changeset/pre.json 2>/dev/null || echo '')
43 |             
44 |             if [ "$MODE" = "exit" ]; then
45 |               echo "Pre-release mode is in 'exit' state, re-entering RC mode..."
46 |               npx changeset pre enter rc
47 |             elif [ "$MODE" = "pre" ] && [ "$TAG" != "rc" ]; then
48 |               echo "In pre-release mode but with wrong tag ($TAG), switching to RC..."
49 |               npx changeset pre exit
50 |               npx changeset pre enter rc
51 |             elif [ "$MODE" = "pre" ] && [ "$TAG" = "rc" ]; then
52 |               echo "Already in RC pre-release mode"
53 |             else
54 |               echo "Unknown mode state: $MODE, entering RC mode..."
55 |               npx changeset pre enter rc
56 |             fi
57 |           else
58 |             echo "No pre.json found, entering RC mode..."
59 |             npx changeset pre enter rc
60 |           fi
61 | 
62 |       - name: Version RC packages
63 |         run: npx changeset version
64 |         env:
65 |           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
66 |           NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
67 | 
68 |       - name: Run format
69 |         run: npm run format
70 |         env:
71 |           FORCE_COLOR: 1
72 | 
73 |       - name: Build packages
74 |         run: npm run turbo:build
75 |         env:
76 |           NODE_ENV: production
77 |           FORCE_COLOR: 1
78 |           TM_PUBLIC_BASE_DOMAIN: ${{ secrets.TM_PUBLIC_BASE_DOMAIN }}
79 |           TM_PUBLIC_SUPABASE_URL: ${{ secrets.TM_PUBLIC_SUPABASE_URL }}
80 |           TM_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.TM_PUBLIC_SUPABASE_ANON_KEY }}
81 | 
82 |       - name: Create Release Candidate Pull Request or Publish Release Candidate to npm
83 |         uses: changesets/action@v1
84 |         with:
85 |           publish: npx changeset publish
86 |         env:
87 |           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
88 |           NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
89 | 
90 |       - name: Commit & Push changes
91 |         uses: actions-js/push@master
92 |         with:
93 |           github_token: ${{ secrets.GITHUB_TOKEN }}
94 |           branch: ${{ github.ref }}
95 |           message: "chore: rc version bump"
96 | 
```

--------------------------------------------------------------------------------
/apps/extension/src/webview/components/ErrorBoundary.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Error Boundary Component
  3 |  */
  4 | 
  5 | import React from 'react';
  6 | 
  7 | interface ErrorBoundaryState {
  8 | 	hasError: boolean;
  9 | 	error?: Error;
 10 | 	errorInfo?: React.ErrorInfo;
 11 | }
 12 | 
 13 | interface ErrorBoundaryProps {
 14 | 	children: React.ReactNode;
 15 | 	onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
 16 | }
 17 | 
 18 | export class ErrorBoundary extends React.Component<
 19 | 	ErrorBoundaryProps,
 20 | 	ErrorBoundaryState
 21 | > {
 22 | 	constructor(props: ErrorBoundaryProps) {
 23 | 		super(props);
 24 | 		this.state = { hasError: false };
 25 | 	}
 26 | 
 27 | 	static getDerivedStateFromError(error: Error): ErrorBoundaryState {
 28 | 		return { hasError: true, error };
 29 | 	}
 30 | 
 31 | 	componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
 32 | 		console.error('React Error Boundary caught:', error, errorInfo);
 33 | 
 34 | 		// Log to extension
 35 | 		if (this.props.onError) {
 36 | 			this.props.onError(error, errorInfo);
 37 | 		}
 38 | 
 39 | 		// Send error to extension for centralized handling
 40 | 		if (window.acquireVsCodeApi) {
 41 | 			const vscode = window.acquireVsCodeApi();
 42 | 			vscode.postMessage({
 43 | 				type: 'reactError',
 44 | 				data: {
 45 | 					message: error.message,
 46 | 					stack: error.stack,
 47 | 					componentStack: errorInfo.componentStack,
 48 | 					timestamp: Date.now()
 49 | 				}
 50 | 			});
 51 | 		}
 52 | 	}
 53 | 
 54 | 	render() {
 55 | 		if (this.state.hasError) {
 56 | 			return (
 57 | 				<div className="min-h-screen flex items-center justify-center bg-vscode-background">
 58 | 					<div className="max-w-md mx-auto text-center p-6">
 59 | 						<div className="w-16 h-16 mx-auto mb-4 text-red-400">
 60 | 							<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
 61 | 								<path
 62 | 									strokeLinecap="round"
 63 | 									strokeLinejoin="round"
 64 | 									strokeWidth={2}
 65 | 									d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.962-.833-2.732 0L3.732 19c-.77.833.192 2.5 1.732 2.5z"
 66 | 								/>
 67 | 							</svg>
 68 | 						</div>
 69 | 						<h2 className="text-xl font-semibold text-vscode-foreground mb-2">
 70 | 							Something went wrong
 71 | 						</h2>
 72 | 						<p className="text-vscode-foreground/70 mb-4">
 73 | 							The Task Master Kanban board encountered an unexpected error.
 74 | 						</p>
 75 | 						<div className="space-y-2">
 76 | 							<button
 77 | 								onClick={() =>
 78 | 									this.setState({
 79 | 										hasError: false,
 80 | 										error: undefined,
 81 | 										errorInfo: undefined
 82 | 									})
 83 | 								}
 84 | 								className="w-full px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-md transition-colors"
 85 | 							>
 86 | 								Try Again
 87 | 							</button>
 88 | 							<button
 89 | 								onClick={() => window.location.reload()}
 90 | 								className="w-full px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded-md transition-colors"
 91 | 							>
 92 | 								Reload Extension
 93 | 							</button>
 94 | 						</div>
 95 | 						{this.state.error && (
 96 | 							<details className="mt-4 text-left">
 97 | 								<summary className="text-sm text-vscode-foreground/50 cursor-pointer">
 98 | 									Error Details
 99 | 								</summary>
100 | 								<pre className="mt-2 text-xs text-vscode-foreground/70 bg-vscode-input/30 p-2 rounded overflow-auto max-h-32">
101 | 									{this.state.error.message}
102 | 									{this.state.error.stack && `\n\n${this.state.error.stack}`}
103 | 								</pre>
104 | 							</details>
105 | 						)}
106 | 					</div>
107 | 				</div>
108 | 			);
109 | 		}
110 | 
111 | 		return this.props.children;
112 | 	}
113 | }
114 | 
```

--------------------------------------------------------------------------------
/packages/tm-core/src/modules/auth/auth-domain.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Auth Domain tests
  3 |  */
  4 | 
  5 | import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
  6 | import { AuthDomain } from './auth-domain.js';
  7 | 
  8 | describe('AuthDomain', () => {
  9 | 	let authDomain: AuthDomain;
 10 | 	let originalEnv: NodeJS.ProcessEnv;
 11 | 
 12 | 	beforeEach(() => {
 13 | 		// Save original environment
 14 | 		originalEnv = { ...process.env };
 15 | 		authDomain = new AuthDomain();
 16 | 	});
 17 | 
 18 | 	afterEach(() => {
 19 | 		// Restore original environment
 20 | 		process.env = originalEnv;
 21 | 		vi.clearAllMocks();
 22 | 	});
 23 | 
 24 | 	describe('getBriefCreationUrl', () => {
 25 | 		it('should return null if no base domain is configured', () => {
 26 | 			// Clear environment variables
 27 | 			delete process.env.TM_BASE_DOMAIN;
 28 | 			delete process.env.TM_PUBLIC_BASE_DOMAIN;
 29 | 
 30 | 			// Create fresh instance with cleared env
 31 | 			const domain = new AuthDomain();
 32 | 			const url = domain.getBriefCreationUrl();
 33 | 
 34 | 			expect(url).toBeNull();
 35 | 		});
 36 | 
 37 | 		it('should return null if org slug is not available in context', () => {
 38 | 			// Set base domain but context will have no orgSlug
 39 | 			process.env.TM_BASE_DOMAIN = 'localhost:8080';
 40 | 
 41 | 			const domain = new AuthDomain();
 42 | 			// Mock getContext to return null (no context set)
 43 | 			vi.spyOn(domain, 'getContext').mockReturnValue(null);
 44 | 
 45 | 			const url = domain.getBriefCreationUrl();
 46 | 
 47 | 			expect(url).toBeNull();
 48 | 		});
 49 | 
 50 | 		it('should construct URL with http protocol for localhost', () => {
 51 | 			process.env.TM_BASE_DOMAIN = 'localhost:8080';
 52 | 
 53 | 			// Mock getContext to return a context with orgSlug
 54 | 			const domain = new AuthDomain();
 55 | 			vi.spyOn(domain, 'getContext').mockReturnValue({
 56 | 				orgSlug: 'test-org',
 57 | 				updatedAt: new Date().toISOString()
 58 | 			});
 59 | 
 60 | 			const url = domain.getBriefCreationUrl();
 61 | 
 62 | 			expect(url).toBe('http://localhost:8080/home/test-org/briefs/create');
 63 | 		});
 64 | 
 65 | 		it('should construct URL with https protocol for production domain', () => {
 66 | 			process.env.TM_BASE_DOMAIN = 'tryhamster.com';
 67 | 
 68 | 			const domain = new AuthDomain();
 69 | 			vi.spyOn(domain, 'getContext').mockReturnValue({
 70 | 				orgSlug: 'acme-corp',
 71 | 				updatedAt: new Date().toISOString()
 72 | 			});
 73 | 
 74 | 			const url = domain.getBriefCreationUrl();
 75 | 
 76 | 			expect(url).toBe('https://tryhamster.com/home/acme-corp/briefs/create');
 77 | 		});
 78 | 
 79 | 		it('should use existing protocol if base domain includes it', () => {
 80 | 			process.env.TM_BASE_DOMAIN = 'https://staging.hamster.dev';
 81 | 
 82 | 			const domain = new AuthDomain();
 83 | 			vi.spyOn(domain, 'getContext').mockReturnValue({
 84 | 				orgSlug: 'staging-org',
 85 | 				updatedAt: new Date().toISOString()
 86 | 			});
 87 | 
 88 | 			const url = domain.getBriefCreationUrl();
 89 | 
 90 | 			expect(url).toBe(
 91 | 				'https://staging.hamster.dev/home/staging-org/briefs/create'
 92 | 			);
 93 | 		});
 94 | 
 95 | 		it('should prefer TM_BASE_DOMAIN over TM_PUBLIC_BASE_DOMAIN', () => {
 96 | 			process.env.TM_BASE_DOMAIN = 'localhost:8080';
 97 | 			process.env.TM_PUBLIC_BASE_DOMAIN = 'tryhamster.com';
 98 | 
 99 | 			const domain = new AuthDomain();
100 | 			vi.spyOn(domain, 'getContext').mockReturnValue({
101 | 				orgSlug: 'my-org',
102 | 				updatedAt: new Date().toISOString()
103 | 			});
104 | 
105 | 			const url = domain.getBriefCreationUrl();
106 | 
107 | 			// Should use TM_BASE_DOMAIN (localhost), not TM_PUBLIC_BASE_DOMAIN
108 | 			expect(url).toBe('http://localhost:8080/home/my-org/briefs/create');
109 | 		});
110 | 	});
111 | });
112 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/rename-tag.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * rename-tag.js
  3 |  * Direct function implementation for renaming a tag
  4 |  */
  5 | 
  6 | import { renameTag } from '../../../../scripts/modules/task-manager/tag-management.js';
  7 | import {
  8 | 	enableSilentMode,
  9 | 	disableSilentMode
 10 | } from '../../../../scripts/modules/utils.js';
 11 | import { createLogWrapper } from '../../tools/utils.js';
 12 | 
 13 | /**
 14 |  * Direct function wrapper for renaming a tag with error handling.
 15 |  *
 16 |  * @param {Object} args - Command arguments
 17 |  * @param {string} args.oldName - Current name of the tag to rename
 18 |  * @param {string} args.newName - New name for the tag
 19 |  * @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
 20 |  * @param {string} [args.projectRoot] - Project root path
 21 |  * @param {Object} log - Logger object
 22 |  * @param {Object} context - Additional context (session)
 23 |  * @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
 24 |  */
 25 | export async function renameTagDirect(args, log, context = {}) {
 26 | 	// Destructure expected args
 27 | 	const { tasksJsonPath, oldName, newName, projectRoot } = args;
 28 | 	const { session } = context;
 29 | 
 30 | 	// Enable silent mode to prevent console logs from interfering with JSON response
 31 | 	enableSilentMode();
 32 | 
 33 | 	// Create logger wrapper using the utility
 34 | 	const mcpLog = createLogWrapper(log);
 35 | 
 36 | 	try {
 37 | 		// Check if tasksJsonPath was provided
 38 | 		if (!tasksJsonPath) {
 39 | 			log.error('renameTagDirect called without tasksJsonPath');
 40 | 			disableSilentMode();
 41 | 			return {
 42 | 				success: false,
 43 | 				error: {
 44 | 					code: 'MISSING_ARGUMENT',
 45 | 					message: 'tasksJsonPath is required'
 46 | 				}
 47 | 			};
 48 | 		}
 49 | 
 50 | 		// Check required parameters
 51 | 		if (!oldName || typeof oldName !== 'string') {
 52 | 			log.error('Missing required parameter: oldName');
 53 | 			disableSilentMode();
 54 | 			return {
 55 | 				success: false,
 56 | 				error: {
 57 | 					code: 'MISSING_PARAMETER',
 58 | 					message: 'Old tag name is required and must be a string'
 59 | 				}
 60 | 			};
 61 | 		}
 62 | 
 63 | 		if (!newName || typeof newName !== 'string') {
 64 | 			log.error('Missing required parameter: newName');
 65 | 			disableSilentMode();
 66 | 			return {
 67 | 				success: false,
 68 | 				error: {
 69 | 					code: 'MISSING_PARAMETER',
 70 | 					message: 'New tag name is required and must be a string'
 71 | 				}
 72 | 			};
 73 | 		}
 74 | 
 75 | 		log.info(`Renaming tag from "${oldName}" to "${newName}"`);
 76 | 
 77 | 		// Call the renameTag function
 78 | 		const result = await renameTag(
 79 | 			tasksJsonPath,
 80 | 			oldName,
 81 | 			newName,
 82 | 			{}, // options (empty for now)
 83 | 			{
 84 | 				session,
 85 | 				mcpLog,
 86 | 				projectRoot
 87 | 			},
 88 | 			'json' // outputFormat - use 'json' to suppress CLI UI
 89 | 		);
 90 | 
 91 | 		// Restore normal logging
 92 | 		disableSilentMode();
 93 | 
 94 | 		return {
 95 | 			success: true,
 96 | 			data: {
 97 | 				oldName: result.oldName,
 98 | 				newName: result.newName,
 99 | 				renamed: result.renamed,
100 | 				taskCount: result.taskCount,
101 | 				wasCurrentTag: result.wasCurrentTag,
102 | 				message: `Successfully renamed tag from "${result.oldName}" to "${result.newName}"`
103 | 			}
104 | 		};
105 | 	} catch (error) {
106 | 		// Make sure to restore normal logging even if there's an error
107 | 		disableSilentMode();
108 | 
109 | 		log.error(`Error in renameTagDirect: ${error.message}`);
110 | 		return {
111 | 			success: false,
112 | 			error: {
113 | 				code: error.code || 'RENAME_TAG_ERROR',
114 | 				message: error.message
115 | 			}
116 | 		};
117 | 	}
118 | }
119 | 
```

--------------------------------------------------------------------------------
/apps/extension/src/webview/types/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Shared types for the webview application
  3 |  */
  4 | 
  5 | export interface TaskMasterTask {
  6 | 	id: string;
  7 | 	title: string;
  8 | 	description: string;
  9 | 	status: 'pending' | 'in-progress' | 'done' | 'deferred' | 'review';
 10 | 	priority: 'high' | 'medium' | 'low';
 11 | 	dependencies?: string[];
 12 | 	details?: string;
 13 | 	testStrategy?: string;
 14 | 	subtasks?: TaskMasterTask[];
 15 | 	complexityScore?: number;
 16 | }
 17 | 
 18 | export interface TaskUpdates {
 19 | 	title?: string;
 20 | 	description?: string;
 21 | 	details?: string;
 22 | 	priority?: TaskMasterTask['priority'];
 23 | 	testStrategy?: string;
 24 | 	dependencies?: string[];
 25 | }
 26 | 
 27 | export interface WebviewMessage {
 28 | 	type: string;
 29 | 	requestId?: string;
 30 | 	data?: any;
 31 | 	success?: boolean;
 32 | 	[key: string]: any;
 33 | }
 34 | 
 35 | export interface ToastNotification {
 36 | 	id: string;
 37 | 	type: 'success' | 'info' | 'warning' | 'error';
 38 | 	title: string;
 39 | 	message: string;
 40 | 	duration?: number;
 41 | }
 42 | 
 43 | export interface AppState {
 44 | 	tasks: TaskMasterTask[];
 45 | 	loading: boolean;
 46 | 	error?: string;
 47 | 	requestId: number;
 48 | 	isConnected: boolean;
 49 | 	connectionStatus: string;
 50 | 	editingTask?: { taskId: string | null; editData?: TaskMasterTask };
 51 | 	polling: {
 52 | 		isActive: boolean;
 53 | 		errorCount: number;
 54 | 		lastUpdate?: number;
 55 | 		isUserInteracting: boolean;
 56 | 		isOfflineMode: boolean;
 57 | 		reconnectAttempts: number;
 58 | 		maxReconnectAttempts: number;
 59 | 		lastSuccessfulConnection?: number;
 60 | 		connectionStatus: 'online' | 'offline' | 'reconnecting';
 61 | 	};
 62 | 	toastNotifications: ToastNotification[];
 63 | 	currentView: 'kanban' | 'task-details' | 'config';
 64 | 	selectedTaskId?: string;
 65 | 	// Tag-related state
 66 | 	currentTag: string;
 67 | 	availableTags: string[];
 68 | }
 69 | 
 70 | export type AppAction =
 71 | 	| { type: 'SET_TASKS'; payload: TaskMasterTask[] }
 72 | 	| { type: 'SET_LOADING'; payload: boolean }
 73 | 	| { type: 'SET_ERROR'; payload: string }
 74 | 	| { type: 'CLEAR_ERROR' }
 75 | 	| { type: 'INCREMENT_REQUEST_ID' }
 76 | 	| {
 77 | 			type: 'UPDATE_TASK_STATUS';
 78 | 			payload: { taskId: string; newStatus: TaskMasterTask['status'] };
 79 | 	  }
 80 | 	| {
 81 | 			type: 'UPDATE_TASK_CONTENT';
 82 | 			payload: { taskId: string; updates: TaskUpdates };
 83 | 	  }
 84 | 	| {
 85 | 			type: 'SET_CONNECTION_STATUS';
 86 | 			payload: { isConnected: boolean; status: string };
 87 | 	  }
 88 | 	| {
 89 | 			type: 'SET_EDITING_TASK';
 90 | 			payload: { taskId: string | null; editData?: TaskMasterTask };
 91 | 	  }
 92 | 	| {
 93 | 			type: 'SET_POLLING_STATUS';
 94 | 			payload: { isActive: boolean; errorCount?: number };
 95 | 	  }
 96 | 	| { type: 'SET_USER_INTERACTING'; payload: boolean }
 97 | 	| { type: 'TASKS_UPDATED_FROM_POLLING'; payload: TaskMasterTask[] }
 98 | 	| {
 99 | 			type: 'SET_NETWORK_STATUS';
100 | 			payload: {
101 | 				isOfflineMode: boolean;
102 | 				connectionStatus: 'online' | 'offline' | 'reconnecting';
103 | 				reconnectAttempts?: number;
104 | 				maxReconnectAttempts?: number;
105 | 				lastSuccessfulConnection?: number;
106 | 			};
107 | 	  }
108 | 	| { type: 'LOAD_CACHED_TASKS'; payload: TaskMasterTask[] }
109 | 	| { type: 'ADD_TOAST'; payload: ToastNotification }
110 | 	| { type: 'REMOVE_TOAST'; payload: string }
111 | 	| { type: 'CLEAR_ALL_TOASTS' }
112 | 	| { type: 'NAVIGATE_TO_TASK'; payload: string }
113 | 	| { type: 'NAVIGATE_TO_KANBAN' }
114 | 	| { type: 'NAVIGATE_TO_CONFIG' }
115 | 	| { type: 'SET_CURRENT_TAG'; payload: string }
116 | 	| { type: 'SET_AVAILABLE_TAGS'; payload: string[] }
117 | 	| {
118 | 			type: 'SET_TAG_DATA';
119 | 			payload: { currentTag: string; availableTags: string[] };
120 | 	  };
121 | 
```

--------------------------------------------------------------------------------
/.github/workflows/extension-ci.yml:
--------------------------------------------------------------------------------

```yaml
  1 | name: Extension CI
  2 | 
  3 | on:
  4 |   push:
  5 |     branches:
  6 |       - main
  7 |       - next
  8 |     paths:
  9 |       - "apps/extension/**"
 10 |       - ".github/workflows/extension-ci.yml"
 11 |   pull_request:
 12 |     branches:
 13 |       - main
 14 |       - next
 15 |     paths:
 16 |       - "apps/extension/**"
 17 |       - ".github/workflows/extension-ci.yml"
 18 | 
 19 | permissions:
 20 |   contents: read
 21 | 
 22 | jobs:
 23 |   setup:
 24 |     runs-on: ubuntu-latest
 25 |     steps:
 26 |       - uses: actions/checkout@v4
 27 |         with:
 28 |           fetch-depth: 0
 29 | 
 30 |       - uses: actions/setup-node@v4
 31 |         with:
 32 |           node-version: 20
 33 | 
 34 |       - name: Cache node_modules
 35 |         uses: actions/cache@v4
 36 |         with:
 37 |           path: |
 38 |             node_modules
 39 |             */*/node_modules
 40 |           key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
 41 |           restore-keys: |
 42 |             ${{ runner.os }}-node-
 43 | 
 44 |       - name: Install Monorepo Dependencies
 45 |         run: npm ci
 46 |         timeout-minutes: 5
 47 | 
 48 |   typecheck:
 49 |     needs: setup
 50 |     runs-on: ubuntu-latest
 51 |     steps:
 52 |       - uses: actions/checkout@v4
 53 | 
 54 |       - uses: actions/setup-node@v4
 55 |         with:
 56 |           node-version: 20
 57 | 
 58 |       - name: Restore node_modules
 59 |         uses: actions/cache@v4
 60 |         with:
 61 |           path: |
 62 |             node_modules
 63 |             */*/node_modules
 64 |           key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
 65 |           restore-keys: |
 66 |             ${{ runner.os }}-node-
 67 | 
 68 |       - name: Install if cache miss
 69 |         run: npm ci
 70 |         timeout-minutes: 3
 71 | 
 72 |       - name: Type Check Extension
 73 |         working-directory: apps/extension
 74 |         run: npm run typecheck
 75 |         env:
 76 |           FORCE_COLOR: 1
 77 | 
 78 |   build:
 79 |     needs: setup
 80 |     runs-on: ubuntu-latest
 81 |     steps:
 82 |       - uses: actions/checkout@v4
 83 | 
 84 |       - uses: actions/setup-node@v4
 85 |         with:
 86 |           node-version: 20
 87 | 
 88 |       - name: Restore node_modules
 89 |         uses: actions/cache@v4
 90 |         with:
 91 |           path: |
 92 |             node_modules
 93 |             */*/node_modules
 94 |           key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
 95 |           restore-keys: |
 96 |             ${{ runner.os }}-node-
 97 | 
 98 |       - name: Install if cache miss
 99 |         run: npm ci
100 |         timeout-minutes: 3
101 | 
102 |       - name: Build Extension
103 |         working-directory: apps/extension
104 |         run: npm run build
105 |         env:
106 |           FORCE_COLOR: 1
107 | 
108 |       - name: Package Extension
109 |         working-directory: apps/extension
110 |         run: npm run package
111 |         env:
112 |           FORCE_COLOR: 1
113 | 
114 |       - name: Verify Package Contents
115 |         working-directory: apps/extension
116 |         run: |
117 |           echo "Checking vsix-build contents..."
118 |           ls -la vsix-build/
119 |           echo "Checking dist contents..."
120 |           ls -la vsix-build/dist/
121 |           echo "Checking package.json exists..."
122 |           test -f vsix-build/package.json
123 | 
124 |       - name: Create VSIX Package (Test)
125 |         working-directory: apps/extension/vsix-build
126 |         run: npx vsce package --no-dependencies
127 |         env:
128 |           FORCE_COLOR: 1
129 | 
130 |       - name: Upload Extension Artifact
131 |         uses: actions/upload-artifact@v4
132 |         with:
133 |           name: extension-package
134 |           path: |
135 |             apps/extension/vsix-build/*.vsix
136 |             apps/extension/dist/
137 |           retention-days: 30
138 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/tools/add-task.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * tools/add-task.js
  3 |  * Tool to add a new task using AI
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	createErrorResponse,
  9 | 	handleApiResult,
 10 | 	withNormalizedProjectRoot
 11 | } from './utils.js';
 12 | import { addTaskDirect } from '../core/task-master-core.js';
 13 | import { findTasksPath } from '../core/utils/path-utils.js';
 14 | import { resolveTag } from '../../../scripts/modules/utils.js';
 15 | 
 16 | /**
 17 |  * Register the addTask tool with the MCP server
 18 |  * @param {Object} server - FastMCP server instance
 19 |  */
 20 | export function registerAddTaskTool(server) {
 21 | 	server.addTool({
 22 | 		name: 'add_task',
 23 | 		description: 'Add a new task using AI',
 24 | 		parameters: z.object({
 25 | 			prompt: z
 26 | 				.string()
 27 | 				.optional()
 28 | 				.describe(
 29 | 					'Description of the task to add (required if not using manual fields)'
 30 | 				),
 31 | 			title: z
 32 | 				.string()
 33 | 				.optional()
 34 | 				.describe('Task title (for manual task creation)'),
 35 | 			description: z
 36 | 				.string()
 37 | 				.optional()
 38 | 				.describe('Task description (for manual task creation)'),
 39 | 			details: z
 40 | 				.string()
 41 | 				.optional()
 42 | 				.describe('Implementation details (for manual task creation)'),
 43 | 			testStrategy: z
 44 | 				.string()
 45 | 				.optional()
 46 | 				.describe('Test strategy (for manual task creation)'),
 47 | 			dependencies: z
 48 | 				.string()
 49 | 				.optional()
 50 | 				.describe('Comma-separated list of task IDs this task depends on'),
 51 | 			priority: z
 52 | 				.string()
 53 | 				.optional()
 54 | 				.describe('Task priority (high, medium, low)'),
 55 | 			file: z
 56 | 				.string()
 57 | 				.optional()
 58 | 				.describe('Path to the tasks file (default: tasks/tasks.json)'),
 59 | 			projectRoot: z
 60 | 				.string()
 61 | 				.describe('The directory of the project. Must be an absolute path.'),
 62 | 			tag: z.string().optional().describe('Tag context to operate on'),
 63 | 			research: z
 64 | 				.boolean()
 65 | 				.optional()
 66 | 				.describe('Whether to use research capabilities for task creation')
 67 | 		}),
 68 | 		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
 69 | 			try {
 70 | 				log.info(`Starting add-task with args: ${JSON.stringify(args)}`);
 71 | 
 72 | 				const resolvedTag = resolveTag({
 73 | 					projectRoot: args.projectRoot,
 74 | 					tag: args.tag
 75 | 				});
 76 | 
 77 | 				// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
 78 | 				let tasksJsonPath;
 79 | 				try {
 80 | 					tasksJsonPath = findTasksPath(
 81 | 						{ projectRoot: args.projectRoot, file: args.file },
 82 | 						log
 83 | 					);
 84 | 				} catch (error) {
 85 | 					log.error(`Error finding tasks.json: ${error.message}`);
 86 | 					return createErrorResponse(
 87 | 						`Failed to find tasks.json: ${error.message}`
 88 | 					);
 89 | 				}
 90 | 
 91 | 				// Call the direct functionP
 92 | 				const result = await addTaskDirect(
 93 | 					{
 94 | 						tasksJsonPath: tasksJsonPath,
 95 | 						prompt: args.prompt,
 96 | 						title: args.title,
 97 | 						description: args.description,
 98 | 						details: args.details,
 99 | 						testStrategy: args.testStrategy,
100 | 						dependencies: args.dependencies,
101 | 						priority: args.priority,
102 | 						research: args.research,
103 | 						projectRoot: args.projectRoot,
104 | 						tag: resolvedTag
105 | 					},
106 | 					log,
107 | 					{ session }
108 | 				);
109 | 
110 | 				return handleApiResult(
111 | 					result,
112 | 					log,
113 | 					'Error adding task',
114 | 					undefined,
115 | 					args.projectRoot
116 | 				);
117 | 			} catch (error) {
118 | 				log.error(`Error in add-task tool: ${error.message}`);
119 | 				return createErrorResponse(error.message);
120 | 			}
121 | 		})
122 | 	});
123 | }
124 | 
```

--------------------------------------------------------------------------------
/tests/integration/profiles/gemini-init-functionality.test.js:
--------------------------------------------------------------------------------

```javascript
 1 | import fs from 'fs';
 2 | import path from 'path';
 3 | import { geminiProfile } from '../../../src/profiles/gemini.js';
 4 | 
 5 | describe('Gemini Profile Initialization Functionality', () => {
 6 | 	let geminiProfileContent;
 7 | 
 8 | 	beforeAll(() => {
 9 | 		const geminiJsPath = path.join(
10 | 			process.cwd(),
11 | 			'src',
12 | 			'profiles',
13 | 			'gemini.js'
14 | 		);
15 | 		geminiProfileContent = fs.readFileSync(geminiJsPath, 'utf8');
16 | 	});
17 | 
18 | 	test('gemini.js has correct profile configuration', () => {
19 | 		// Check for explicit, non-default values in the source file
20 | 		expect(geminiProfileContent).toContain("name: 'gemini'");
21 | 		expect(geminiProfileContent).toContain("displayName: 'Gemini'");
22 | 		expect(geminiProfileContent).toContain("url: 'codeassist.google'");
23 | 		expect(geminiProfileContent).toContain(
24 | 			"docsUrl: 'github.com/google-gemini/gemini-cli'"
25 | 		);
26 | 		expect(geminiProfileContent).toContain("profileDir: '.gemini'");
27 | 		expect(geminiProfileContent).toContain("rulesDir: '.'"); // non-default
28 | 		expect(geminiProfileContent).toContain("mcpConfigName: 'settings.json'"); // non-default
29 | 		expect(geminiProfileContent).toContain('includeDefaultRules: false'); // non-default
30 | 		expect(geminiProfileContent).toContain("'AGENT.md': 'AGENTS.md'");
31 | 		expect(geminiProfileContent).toContain("'GEMINI.md': 'GEMINI.md'");
32 | 
33 | 		// Check the final computed properties on the profile object
34 | 		expect(geminiProfile.profileName).toBe('gemini');
35 | 		expect(geminiProfile.displayName).toBe('Gemini');
36 | 		expect(geminiProfile.profileDir).toBe('.gemini');
37 | 		expect(geminiProfile.rulesDir).toBe('.');
38 | 		expect(geminiProfile.mcpConfig).toBe(true); // computed from mcpConfigName
39 | 		expect(geminiProfile.mcpConfigName).toBe('settings.json');
40 | 		expect(geminiProfile.mcpConfigPath).toBe('.gemini/settings.json'); // computed
41 | 		expect(geminiProfile.includeDefaultRules).toBe(false);
42 | 		expect(geminiProfile.fileMap['AGENT.md']).toBe('AGENTS.md');
43 | 		expect(geminiProfile.fileMap['GEMINI.md']).toBe('GEMINI.md');
44 | 	});
45 | 
46 | 	test('gemini.js has no lifecycle functions', () => {
47 | 		// Gemini profile should not have any lifecycle functions
48 | 		expect(geminiProfileContent).not.toContain('function onAddRulesProfile');
49 | 		expect(geminiProfileContent).not.toContain('function onRemoveRulesProfile');
50 | 		expect(geminiProfileContent).not.toContain(
51 | 			'function onPostConvertRulesProfile'
52 | 		);
53 | 		expect(geminiProfileContent).not.toContain('onAddRulesProfile:');
54 | 		expect(geminiProfileContent).not.toContain('onRemoveRulesProfile:');
55 | 		expect(geminiProfileContent).not.toContain('onPostConvertRulesProfile:');
56 | 	});
57 | 
58 | 	test('gemini.js uses custom MCP config name', () => {
59 | 		// Gemini uses settings.json instead of mcp.json
60 | 		expect(geminiProfileContent).toContain("mcpConfigName: 'settings.json'");
61 | 		// Should not contain mcp.json as a config value (comments are OK)
62 | 		expect(geminiProfileContent).not.toMatch(
63 | 			/mcpConfigName:\s*['"]mcp\.json['"]/
64 | 		);
65 | 	});
66 | 
67 | 	test('gemini.js has minimal implementation', () => {
68 | 		// Verify the profile is minimal (no extra functions or logic)
69 | 		const lines = geminiProfileContent.split('\n');
70 | 		const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
71 | 		// Should be around 16 lines (import, export, and profile definition)
72 | 		expect(nonEmptyLines.length).toBeLessThan(20);
73 | 	});
74 | });
75 | 
```

--------------------------------------------------------------------------------
/tests/integration/profiles/rules-files-inclusion.test.js:
--------------------------------------------------------------------------------

```javascript
 1 | import { jest } from '@jest/globals';
 2 | import fs from 'fs';
 3 | import path from 'path';
 4 | import os from 'os';
 5 | import { execSync } from 'child_process';
 6 | 
 7 | describe('Rules Files Inclusion in Package', () => {
 8 | 	// This test verifies that the required rules files are included in the final package
 9 | 
10 | 	test('package.json includes dist/** in the "files" array for bundled files', () => {
11 | 		// Read the package.json file
12 | 		const packageJsonPath = path.join(process.cwd(), 'package.json');
13 | 		const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
14 | 
15 | 		// Check if dist/** is included in the files array (which contains bundled output including assets)
16 | 		expect(packageJson.files).toContain('dist/**');
17 | 	});
18 | 
19 | 	test('source rules files exist in assets/rules directory', () => {
20 | 		// Verify that the actual rules files exist
21 | 		const rulesDir = path.join(process.cwd(), 'assets', 'rules');
22 | 		expect(fs.existsSync(rulesDir)).toBe(true);
23 | 
24 | 		// Check for the 4 files that currently exist
25 | 		const expectedFiles = [
26 | 			'dev_workflow.mdc',
27 | 			'taskmaster.mdc',
28 | 			'self_improve.mdc',
29 | 			'cursor_rules.mdc'
30 | 		];
31 | 
32 | 		expectedFiles.forEach((file) => {
33 | 			const filePath = path.join(rulesDir, file);
34 | 			expect(fs.existsSync(filePath)).toBe(true);
35 | 		});
36 | 	});
37 | 
38 | 	test('roo.js profile contains logic for Roo directory creation and file copying', () => {
39 | 		// Read the roo.js profile file
40 | 		const rooJsPath = path.join(process.cwd(), 'src', 'profiles', 'roo.js');
41 | 		const rooJsContent = fs.readFileSync(rooJsPath, 'utf8');
42 | 
43 | 		// Check for the main handler function
44 | 		expect(
45 | 			rooJsContent.includes('onAddRulesProfile(targetDir, assetsDir)')
46 | 		).toBe(true);
47 | 
48 | 		// Check for general recursive copy of assets/roocode
49 | 		expect(
50 | 			rooJsContent.includes('copyRecursiveSync(sourceDir, targetDir)')
51 | 		).toBe(true);
52 | 
53 | 		// Check for updated path handling
54 | 		expect(rooJsContent.includes("path.join(assetsDir, 'roocode')")).toBe(true);
55 | 
56 | 		// Check for .roomodes file copying logic (source and destination paths)
57 | 		expect(rooJsContent.includes("path.join(sourceDir, '.roomodes')")).toBe(
58 | 			true
59 | 		);
60 | 		expect(rooJsContent.includes("path.join(targetDir, '.roomodes')")).toBe(
61 | 			true
62 | 		);
63 | 
64 | 		// Check for mode-specific rule file copying logic
65 | 		expect(rooJsContent.includes('for (const mode of ROO_MODES)')).toBe(true);
66 | 		expect(
67 | 			rooJsContent.includes(
68 | 				'path.join(rooModesDir, `rules-${mode}`, `${mode}-rules`)'
69 | 			)
70 | 		).toBe(true);
71 | 		expect(
72 | 			rooJsContent.includes(
73 | 				"path.join(targetDir, '.roo', `rules-${mode}`, `${mode}-rules`)"
74 | 			)
75 | 		).toBe(true);
76 | 
77 | 		// Check for import of ROO_MODES from profiles.js
78 | 		expect(
79 | 			rooJsContent.includes(
80 | 				"import { ROO_MODES } from '../constants/profiles.js'"
81 | 			)
82 | 		).toBe(true);
83 | 
84 | 		// Verify mode variable is used in the template strings (this confirms modes are being processed)
85 | 		expect(rooJsContent.includes('rules-${mode}')).toBe(true);
86 | 		expect(rooJsContent.includes('${mode}-rules')).toBe(true);
87 | 	});
88 | 
89 | 	test('source Roo files exist in assets directory', () => {
90 | 		// Verify that the source files for Roo integration exist
91 | 		expect(
92 | 			fs.existsSync(path.join(process.cwd(), 'assets', 'roocode', '.roo'))
93 | 		).toBe(true);
94 | 		expect(
95 | 			fs.existsSync(path.join(process.cwd(), 'assets', 'roocode', '.roomodes'))
96 | 		).toBe(true);
97 | 	});
98 | });
99 | 
```

--------------------------------------------------------------------------------
/tests/unit/profiles/codex-integration.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { jest } from '@jest/globals';
  2 | import fs from 'fs';
  3 | import path from 'path';
  4 | import os from 'os';
  5 | 
  6 | // Mock external modules
  7 | jest.mock('child_process', () => ({
  8 | 	execSync: jest.fn()
  9 | }));
 10 | 
 11 | // Mock console methods
 12 | jest.mock('console', () => ({
 13 | 	log: jest.fn(),
 14 | 	info: jest.fn(),
 15 | 	warn: jest.fn(),
 16 | 	error: jest.fn(),
 17 | 	clear: jest.fn()
 18 | }));
 19 | 
 20 | describe('Codex Profile Integration', () => {
 21 | 	let tempDir;
 22 | 
 23 | 	beforeEach(() => {
 24 | 		jest.clearAllMocks();
 25 | 
 26 | 		// Create a temporary directory for testing
 27 | 		tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'task-master-test-'));
 28 | 
 29 | 		// Spy on fs methods
 30 | 		jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
 31 | 		jest.spyOn(fs, 'readFileSync').mockImplementation((filePath) => {
 32 | 			if (filePath.toString().includes('AGENTS.md')) {
 33 | 				return 'Sample AGENTS.md content for Codex integration';
 34 | 			}
 35 | 			return '{}';
 36 | 		});
 37 | 		jest.spyOn(fs, 'existsSync').mockImplementation(() => false);
 38 | 		jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {});
 39 | 	});
 40 | 
 41 | 	afterEach(() => {
 42 | 		// Clean up the temporary directory
 43 | 		try {
 44 | 			fs.rmSync(tempDir, { recursive: true, force: true });
 45 | 		} catch (err) {
 46 | 			console.error(`Error cleaning up: ${err.message}`);
 47 | 		}
 48 | 	});
 49 | 
 50 | 	// Test function that simulates the Codex profile file copying behavior
 51 | 	function mockCreateCodexStructure() {
 52 | 		// Codex profile copies AGENTS.md to AGENTS.md in project root (same name)
 53 | 		const sourceContent = 'Sample AGENTS.md content for Codex integration';
 54 | 		fs.writeFileSync(path.join(tempDir, 'AGENTS.md'), sourceContent);
 55 | 	}
 56 | 
 57 | 	test('creates AGENTS.md file in project root', () => {
 58 | 		// Act
 59 | 		mockCreateCodexStructure();
 60 | 
 61 | 		// Assert
 62 | 		expect(fs.writeFileSync).toHaveBeenCalledWith(
 63 | 			path.join(tempDir, 'AGENTS.md'),
 64 | 			'Sample AGENTS.md content for Codex integration'
 65 | 		);
 66 | 	});
 67 | 
 68 | 	test('does not create any profile directories', () => {
 69 | 		// Act
 70 | 		mockCreateCodexStructure();
 71 | 
 72 | 		// Assert - Codex profile should not create any directories
 73 | 		// Only the temp directory creation calls should exist
 74 | 		const mkdirCalls = fs.mkdirSync.mock.calls.filter(
 75 | 			(call) => !call[0].includes('task-master-test-')
 76 | 		);
 77 | 		expect(mkdirCalls).toHaveLength(0);
 78 | 	});
 79 | 
 80 | 	test('does not create MCP configuration files', () => {
 81 | 		// Act
 82 | 		mockCreateCodexStructure();
 83 | 
 84 | 		// Assert - Codex profile should not create any MCP config files
 85 | 		const writeFileCalls = fs.writeFileSync.mock.calls;
 86 | 		const mcpConfigCalls = writeFileCalls.filter(
 87 | 			(call) =>
 88 | 				call[0].toString().includes('mcp.json') ||
 89 | 				call[0].toString().includes('mcp_settings.json')
 90 | 		);
 91 | 		expect(mcpConfigCalls).toHaveLength(0);
 92 | 	});
 93 | 
 94 | 	test('only creates the target integration guide file', () => {
 95 | 		// Act
 96 | 		mockCreateCodexStructure();
 97 | 
 98 | 		// Assert - Should only create AGENTS.md
 99 | 		const writeFileCalls = fs.writeFileSync.mock.calls;
100 | 		expect(writeFileCalls).toHaveLength(1);
101 | 		expect(writeFileCalls[0][0]).toBe(path.join(tempDir, 'AGENTS.md'));
102 | 	});
103 | 
104 | 	test('uses the same filename as source (AGENTS.md)', () => {
105 | 		// Act
106 | 		mockCreateCodexStructure();
107 | 
108 | 		// Assert - Codex should keep the same filename unlike Claude which renames it
109 | 		const writeFileCalls = fs.writeFileSync.mock.calls;
110 | 		expect(writeFileCalls[0][0]).toContain('AGENTS.md');
111 | 		expect(writeFileCalls[0][0]).not.toContain('CLAUDE.md');
112 | 	});
113 | });
114 | 
```
Page 9/69FirstPrevNextLast