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

--------------------------------------------------------------------------------
/tests/unit/progress/base-progress-tracker.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { jest } from '@jest/globals';
  2 | 
  3 | // Mock cli-progress factory before importing BaseProgressTracker
  4 | jest.unstable_mockModule(
  5 | 	'../../../src/progress/cli-progress-factory.js',
  6 | 	() => ({
  7 | 		newMultiBar: jest.fn(() => ({
  8 | 			create: jest.fn(() => ({
  9 | 				update: jest.fn()
 10 | 			})),
 11 | 			stop: jest.fn()
 12 | 		}))
 13 | 	})
 14 | );
 15 | 
 16 | const { newMultiBar } = await import(
 17 | 	'../../../src/progress/cli-progress-factory.js'
 18 | );
 19 | const { BaseProgressTracker } = await import(
 20 | 	'../../../src/progress/base-progress-tracker.js'
 21 | );
 22 | 
 23 | describe('BaseProgressTracker', () => {
 24 | 	let tracker;
 25 | 	let mockMultiBar;
 26 | 	let mockProgressBar;
 27 | 	let mockTimeTokensBar;
 28 | 
 29 | 	beforeEach(() => {
 30 | 		jest.clearAllMocks();
 31 | 		jest.useFakeTimers();
 32 | 
 33 | 		// Setup mocks
 34 | 		mockProgressBar = { update: jest.fn() };
 35 | 		mockTimeTokensBar = { update: jest.fn() };
 36 | 		mockMultiBar = {
 37 | 			create: jest
 38 | 				.fn()
 39 | 				.mockReturnValueOnce(mockTimeTokensBar)
 40 | 				.mockReturnValueOnce(mockProgressBar),
 41 | 			stop: jest.fn()
 42 | 		};
 43 | 		newMultiBar.mockReturnValue(mockMultiBar);
 44 | 
 45 | 		tracker = new BaseProgressTracker({ numUnits: 10, unitName: 'task' });
 46 | 	});
 47 | 
 48 | 	afterEach(() => {
 49 | 		jest.useRealTimers();
 50 | 	});
 51 | 
 52 | 	describe('cleanup', () => {
 53 | 		it('should stop and clear timer interval', () => {
 54 | 			tracker.start();
 55 | 			expect(tracker._timerInterval).toBeTruthy();
 56 | 
 57 | 			tracker.cleanup();
 58 | 			expect(tracker._timerInterval).toBeNull();
 59 | 		});
 60 | 
 61 | 		it('should stop and null multibar reference', () => {
 62 | 			tracker.start();
 63 | 			expect(tracker.multibar).toBeTruthy();
 64 | 
 65 | 			tracker.cleanup();
 66 | 			expect(mockMultiBar.stop).toHaveBeenCalled();
 67 | 			expect(tracker.multibar).toBeNull();
 68 | 		});
 69 | 
 70 | 		it('should null progress bar references', () => {
 71 | 			tracker.start();
 72 | 			expect(tracker.timeTokensBar).toBeTruthy();
 73 | 			expect(tracker.progressBar).toBeTruthy();
 74 | 
 75 | 			tracker.cleanup();
 76 | 			expect(tracker.timeTokensBar).toBeNull();
 77 | 			expect(tracker.progressBar).toBeNull();
 78 | 		});
 79 | 
 80 | 		it('should set finished state', () => {
 81 | 			tracker.start();
 82 | 			expect(tracker.isStarted).toBe(true);
 83 | 			expect(tracker.isFinished).toBe(false);
 84 | 
 85 | 			tracker.cleanup();
 86 | 			expect(tracker.isStarted).toBe(false);
 87 | 			expect(tracker.isFinished).toBe(true);
 88 | 		});
 89 | 
 90 | 		it('should handle cleanup when multibar.stop throws error', () => {
 91 | 			tracker.start();
 92 | 			mockMultiBar.stop.mockImplementation(() => {
 93 | 				throw new Error('Stop failed');
 94 | 			});
 95 | 
 96 | 			expect(() => tracker.cleanup()).not.toThrow();
 97 | 			expect(tracker.multibar).toBeNull();
 98 | 		});
 99 | 
100 | 		it('should be safe to call multiple times', () => {
101 | 			tracker.start();
102 | 
103 | 			tracker.cleanup();
104 | 			tracker.cleanup();
105 | 			tracker.cleanup();
106 | 
107 | 			expect(mockMultiBar.stop).toHaveBeenCalledTimes(1);
108 | 		});
109 | 
110 | 		it('should be safe to call without starting', () => {
111 | 			expect(() => tracker.cleanup()).not.toThrow();
112 | 			expect(tracker.multibar).toBeNull();
113 | 		});
114 | 	});
115 | 
116 | 	describe('stop vs cleanup', () => {
117 | 		it('stop should call cleanup and null multibar reference', () => {
118 | 			tracker.start();
119 | 			tracker.stop();
120 | 
121 | 			// stop() now calls cleanup() which nulls the multibar
122 | 			expect(tracker.multibar).toBeNull();
123 | 			expect(tracker.isFinished).toBe(true);
124 | 		});
125 | 
126 | 		it('cleanup should null multibar preventing getSummary', () => {
127 | 			tracker.start();
128 | 			tracker.cleanup();
129 | 
130 | 			expect(tracker.multibar).toBeNull();
131 | 			expect(tracker.isFinished).toBe(true);
132 | 		});
133 | 	});
134 | });
135 | 
```

--------------------------------------------------------------------------------
/.taskmaster/reports/task-complexity-report_test-prd-tag.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 | 	"meta": {
 3 | 		"generatedAt": "2025-06-13T06:52:00.611Z",
 4 | 		"tasksAnalyzed": 5,
 5 | 		"totalTasks": 5,
 6 | 		"analysisCount": 5,
 7 | 		"thresholdScore": 5,
 8 | 		"projectName": "Taskmaster",
 9 | 		"usedResearch": true
10 | 	},
11 | 	"complexityAnalysis": [
12 | 		{
13 | 			"taskId": 1,
14 | 			"taskTitle": "Setup Project Repository and Node.js Environment",
15 | 			"complexityScore": 4,
16 | 			"recommendedSubtasks": 6,
17 | 			"expansionPrompt": "Break down the setup process into subtasks such as initializing npm, creating directory structure, installing dependencies, configuring package.json, adding configuration files, and setting up the main entry point.",
18 | 			"reasoning": "This task involves several standard setup steps that are well-defined and sequential, with low algorithmic complexity but moderate procedural detail. Each step is independent and can be assigned as a subtask, making the overall complexity moderate."
19 | 		},
20 | 		{
21 | 			"taskId": 2,
22 | 			"taskTitle": "Implement Core Functionality and CLI Interface",
23 | 			"complexityScore": 7,
24 | 			"recommendedSubtasks": 7,
25 | 			"expansionPrompt": "Expand into subtasks for implementing main logic, designing CLI commands, creating the CLI entry point, integrating business logic, adding error handling, formatting output, and ensuring CLI executability.",
26 | 			"reasoning": "This task requires both application logic and user interface (CLI) development, including error handling and integration. The need to coordinate between core logic and CLI, plus ensuring usability, increases complexity and warrants detailed subtasking."
27 | 		},
28 | 		{
29 | 			"taskId": 3,
30 | 			"taskTitle": "Implement Testing Suite and Validation",
31 | 			"complexityScore": 6,
32 | 			"recommendedSubtasks": 6,
33 | 			"expansionPrompt": "Divide into subtasks for configuring Jest, writing unit tests, writing integration tests, testing CLI commands, setting up coverage reporting, and preparing test fixtures/mocks.",
34 | 			"reasoning": "Comprehensive testing involves multiple types of tests and configuration steps. While each is straightforward, the breadth of coverage and need for automation and validation increases the overall complexity."
35 | 		},
36 | 		{
37 | 			"taskId": 4,
38 | 			"taskTitle": "Setup Node.js Project with CLI Interface",
39 | 			"complexityScore": 5,
40 | 			"recommendedSubtasks": 7,
41 | 			"expansionPrompt": "Break down into subtasks for npm initialization, package.json setup, directory structure creation, dependency installation, CLI entry point creation, package.json bin configuration, and CLI executability.",
42 | 			"reasoning": "This task combines project setup with initial CLI implementation. While each step is standard, the integration of CLI elements adds a layer of complexity beyond a basic setup."
43 | 		},
44 | 		{
45 | 			"taskId": 5,
46 | 			"taskTitle": "Implement Core Functionality with Testing",
47 | 			"complexityScore": 8,
48 | 			"recommendedSubtasks": 8,
49 | 			"expansionPrompt": "Expand into subtasks for implementing each feature (A, B, C), setting up the testing framework, writing tests for each feature, integrating CLI with core logic, and adding coverage reporting.",
50 | 			"reasoning": "This task requires simultaneous development of multiple features, integration with CLI, and comprehensive testing. The coordination and depth required for both implementation and validation make it the most complex among the listed tasks."
51 | 		}
52 | 	]
53 | }
54 | 
```

--------------------------------------------------------------------------------
/src/ai-providers/zai.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * zai.js
  3 |  * AI provider implementation for Z.ai (GLM) models.
  4 |  * Uses the OpenAI-compatible API endpoint.
  5 |  */
  6 | 
  7 | import { OpenAICompatibleProvider } from './openai-compatible.js';
  8 | 
  9 | /**
 10 |  * Z.ai provider supporting GLM models through OpenAI-compatible API.
 11 |  */
 12 | export class ZAIProvider extends OpenAICompatibleProvider {
 13 | 	constructor() {
 14 | 		super({
 15 | 			name: 'Z.ai',
 16 | 			apiKeyEnvVar: 'ZAI_API_KEY',
 17 | 			requiresApiKey: true,
 18 | 			defaultBaseURL: 'https://api.z.ai/api/paas/v4/',
 19 | 			supportsStructuredOutputs: true
 20 | 		});
 21 | 	}
 22 | 
 23 | 	/**
 24 | 	 * Override token parameter preparation for ZAI
 25 | 	 * ZAI API doesn't support max_tokens parameter
 26 | 	 * @returns {object} Empty object for ZAI (doesn't support maxOutputTokens)
 27 | 	 */
 28 | 	prepareTokenParam() {
 29 | 		// ZAI API rejects max_tokens parameter with error code 1210
 30 | 		return {};
 31 | 	}
 32 | 
 33 | 	/**
 34 | 	 * Introspects a Zod schema to find the property that expects an array
 35 | 	 * @param {import('zod').ZodType} schema - The Zod schema to introspect
 36 | 	 * @returns {string|null} The property name that expects an array, or null if not found
 37 | 	 */
 38 | 	findArrayPropertyInSchema(schema) {
 39 | 		try {
 40 | 			// Get the def object from Zod v4 API
 41 | 			const def = schema._zod.def;
 42 | 
 43 | 			// Check if schema is a ZodObject
 44 | 			const isObject = def?.type === 'object' || def?.typeName === 'ZodObject';
 45 | 
 46 | 			if (!isObject) {
 47 | 				return null;
 48 | 			}
 49 | 
 50 | 			// Get the shape - it can be a function, property, or getter
 51 | 			let shape = def.shape;
 52 | 			if (typeof shape === 'function') {
 53 | 				shape = shape();
 54 | 			}
 55 | 
 56 | 			if (!shape || typeof shape !== 'object') {
 57 | 				return null;
 58 | 			}
 59 | 
 60 | 			// Find the first property that is an array
 61 | 			for (const [key, value] of Object.entries(shape)) {
 62 | 				// Get the def object for the property using Zod v4 API
 63 | 				const valueDef = value._zod.def;
 64 | 
 65 | 				// Check if the property is a ZodArray
 66 | 				const isArray =
 67 | 					valueDef?.type === 'array' || valueDef?.typeName === 'ZodArray';
 68 | 
 69 | 				if (isArray) {
 70 | 					return key;
 71 | 				}
 72 | 			}
 73 | 
 74 | 			return null;
 75 | 		} catch (error) {
 76 | 			// If introspection fails, log and return null
 77 | 			console.warn('Failed to introspect Zod schema:', error.message);
 78 | 			return null;
 79 | 		}
 80 | 	}
 81 | 
 82 | 	/**
 83 | 	 * Override generateObject to normalize GLM's response format
 84 | 	 * GLM sometimes returns bare arrays instead of objects with properties,
 85 | 	 * even when the schema has multiple properties.
 86 | 	 * @param {object} params - Parameters for object generation
 87 | 	 * @returns {Promise<object>} Normalized response
 88 | 	 */
 89 | 	async generateObject(params) {
 90 | 		const result = await super.generateObject(params);
 91 | 
 92 | 		// If result.object is an array, wrap it based on schema introspection
 93 | 		if (Array.isArray(result.object)) {
 94 | 			// Try to find the array property from the schema
 95 | 			const wrapperKey = this.findArrayPropertyInSchema(params.schema);
 96 | 
 97 | 			if (wrapperKey) {
 98 | 				return {
 99 | 					...result,
100 | 					object: {
101 | 						[wrapperKey]: result.object
102 | 					}
103 | 				};
104 | 			}
105 | 
106 | 			// Fallback: if we can't introspect the schema, use the object name
107 | 			// This handles edge cases where schema introspection might fail
108 | 			console.warn(
109 | 				`GLM returned a bare array for '${params.objectName}' but could not determine wrapper property from schema. Using objectName as fallback.`
110 | 			);
111 | 
112 | 			return {
113 | 				...result,
114 | 				object: {
115 | 					[params.objectName]: result.object
116 | 				}
117 | 			};
118 | 		}
119 | 
120 | 		return result;
121 | 	}
122 | }
123 | 
```

--------------------------------------------------------------------------------
/.github/scripts/check-pre-release-mode.mjs:
--------------------------------------------------------------------------------

```
  1 | #!/usr/bin/env node
  2 | import { readFileSync, existsSync } from 'node:fs';
  3 | import { join, dirname, resolve } from 'node:path';
  4 | import { fileURLToPath } from 'node:url';
  5 | 
  6 | const __filename = fileURLToPath(import.meta.url);
  7 | const __dirname = dirname(__filename);
  8 | 
  9 | // Get context from command line argument or environment
 10 | const context = process.argv[2] || process.env.GITHUB_WORKFLOW || 'manual';
 11 | 
 12 | function findRootDir(startDir) {
 13 | 	let currentDir = resolve(startDir);
 14 | 	while (currentDir !== '/') {
 15 | 		if (existsSync(join(currentDir, 'package.json'))) {
 16 | 			try {
 17 | 				const pkg = JSON.parse(
 18 | 					readFileSync(join(currentDir, 'package.json'), 'utf8')
 19 | 				);
 20 | 				if (pkg.name === 'task-master-ai' || pkg.repository) {
 21 | 					return currentDir;
 22 | 				}
 23 | 			} catch {}
 24 | 		}
 25 | 		currentDir = dirname(currentDir);
 26 | 	}
 27 | 	throw new Error('Could not find root directory');
 28 | }
 29 | 
 30 | function checkPreReleaseMode() {
 31 | 	console.log('🔍 Checking if branch is in pre-release mode...');
 32 | 
 33 | 	const rootDir = findRootDir(__dirname);
 34 | 	const preJsonPath = join(rootDir, '.changeset', 'pre.json');
 35 | 
 36 | 	// Check if pre.json exists
 37 | 	if (!existsSync(preJsonPath)) {
 38 | 		console.log('✅ Not in active pre-release mode - safe to proceed');
 39 | 		process.exit(0);
 40 | 	}
 41 | 
 42 | 	try {
 43 | 		// Read and parse pre.json
 44 | 		const preJsonContent = readFileSync(preJsonPath, 'utf8');
 45 | 		const preJson = JSON.parse(preJsonContent);
 46 | 
 47 | 		// Check if we're in active pre-release mode
 48 | 		if (preJson.mode === 'pre') {
 49 | 			console.error('❌ ERROR: This branch is in active pre-release mode!');
 50 | 			console.error('');
 51 | 
 52 | 			// Provide context-specific error messages
 53 | 			if (context === 'Release Check' || context === 'pull_request') {
 54 | 				console.error(
 55 | 					'Pre-release mode must be exited before merging to main.'
 56 | 				);
 57 | 				console.error('');
 58 | 				console.error(
 59 | 					'To fix this, run the following commands in your branch:'
 60 | 				);
 61 | 				console.error('  npx changeset pre exit');
 62 | 				console.error('  git add -u');
 63 | 				console.error('  git commit -m "chore: exit pre-release mode"');
 64 | 				console.error('  git push');
 65 | 				console.error('');
 66 | 				console.error('Then update this pull request.');
 67 | 			} else if (context === 'Release' || context === 'main') {
 68 | 				console.error(
 69 | 					'Pre-release mode should only be used on feature branches, not main.'
 70 | 				);
 71 | 				console.error('');
 72 | 				console.error('To fix this, run the following commands locally:');
 73 | 				console.error('  npx changeset pre exit');
 74 | 				console.error('  git add -u');
 75 | 				console.error('  git commit -m "chore: exit pre-release mode"');
 76 | 				console.error('  git push origin main');
 77 | 				console.error('');
 78 | 				console.error('Then re-run this workflow.');
 79 | 			} else {
 80 | 				console.error('Pre-release mode must be exited before proceeding.');
 81 | 				console.error('');
 82 | 				console.error('To fix this, run the following commands:');
 83 | 				console.error('  npx changeset pre exit');
 84 | 				console.error('  git add -u');
 85 | 				console.error('  git commit -m "chore: exit pre-release mode"');
 86 | 				console.error('  git push');
 87 | 			}
 88 | 
 89 | 			process.exit(1);
 90 | 		}
 91 | 
 92 | 		console.log('✅ Not in active pre-release mode - safe to proceed');
 93 | 		process.exit(0);
 94 | 	} catch (error) {
 95 | 		console.error(`❌ ERROR: Unable to parse .changeset/pre.json – aborting.`);
 96 | 		console.error(`Error details: ${error.message}`);
 97 | 		process.exit(1);
 98 | 	}
 99 | }
100 | 
101 | // Run the check
102 | checkPreReleaseMode();
103 | 
```

--------------------------------------------------------------------------------
/apps/extension/src/services/config-service.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Config Service
  3 |  * Manages Task Master config.json file operations
  4 |  */
  5 | 
  6 | import * as path from 'path';
  7 | import * as fs from 'fs/promises';
  8 | import * as vscode from 'vscode';
  9 | import type { ExtensionLogger } from '../utils/logger';
 10 | 
 11 | export interface TaskMasterConfigJson {
 12 | 	anthropicApiKey?: string;
 13 | 	perplexityApiKey?: string;
 14 | 	openaiApiKey?: string;
 15 | 	googleApiKey?: string;
 16 | 	xaiApiKey?: string;
 17 | 	openrouterApiKey?: string;
 18 | 	mistralApiKey?: string;
 19 | 	debug?: boolean;
 20 | 	models?: {
 21 | 		main?: string;
 22 | 		research?: string;
 23 | 		fallback?: string;
 24 | 	};
 25 | }
 26 | 
 27 | export class ConfigService {
 28 | 	private configCache: TaskMasterConfigJson | null = null;
 29 | 	private lastReadTime = 0;
 30 | 	private readonly CACHE_DURATION = 5000; // 5 seconds
 31 | 
 32 | 	constructor(private logger: ExtensionLogger) {}
 33 | 
 34 | 	/**
 35 | 	 * Read Task Master config.json from the workspace
 36 | 	 */
 37 | 	async readConfig(): Promise<TaskMasterConfigJson | null> {
 38 | 		// Check cache first
 39 | 		if (
 40 | 			this.configCache &&
 41 | 			Date.now() - this.lastReadTime < this.CACHE_DURATION
 42 | 		) {
 43 | 			return this.configCache;
 44 | 		}
 45 | 
 46 | 		try {
 47 | 			const workspaceRoot = this.getWorkspaceRoot();
 48 | 			if (!workspaceRoot) {
 49 | 				this.logger.warn('No workspace folder found');
 50 | 				return null;
 51 | 			}
 52 | 
 53 | 			const configPath = path.join(workspaceRoot, '.taskmaster', 'config.json');
 54 | 
 55 | 			try {
 56 | 				const configContent = await fs.readFile(configPath, 'utf-8');
 57 | 				const config = JSON.parse(configContent) as TaskMasterConfigJson;
 58 | 
 59 | 				// Cache the result
 60 | 				this.configCache = config;
 61 | 				this.lastReadTime = Date.now();
 62 | 
 63 | 				this.logger.debug('Successfully read Task Master config', {
 64 | 					hasModels: !!config.models,
 65 | 					debug: config.debug
 66 | 				});
 67 | 
 68 | 				return config;
 69 | 			} catch (error) {
 70 | 				if ((error as any).code === 'ENOENT') {
 71 | 					this.logger.debug('Task Master config.json not found');
 72 | 				} else {
 73 | 					this.logger.error('Failed to read Task Master config', error);
 74 | 				}
 75 | 				return null;
 76 | 			}
 77 | 		} catch (error) {
 78 | 			this.logger.error('Error accessing Task Master config', error);
 79 | 			return null;
 80 | 		}
 81 | 	}
 82 | 
 83 | 	/**
 84 | 	 * Get safe config for display (with sensitive data masked)
 85 | 	 */
 86 | 	async getSafeConfig(): Promise<Record<string, any> | null> {
 87 | 		const config = await this.readConfig();
 88 | 		if (!config) {
 89 | 			return null;
 90 | 		}
 91 | 
 92 | 		// Create a safe copy with masked API keys
 93 | 		const safeConfig: Record<string, any> = {
 94 | 			...config
 95 | 		};
 96 | 
 97 | 		// Mask all API keys
 98 | 		const apiKeyFields = [
 99 | 			'anthropicApiKey',
100 | 			'perplexityApiKey',
101 | 			'openaiApiKey',
102 | 			'googleApiKey',
103 | 			'xaiApiKey',
104 | 			'openrouterApiKey',
105 | 			'mistralApiKey'
106 | 		];
107 | 
108 | 		for (const field of apiKeyFields) {
109 | 			if (safeConfig[field]) {
110 | 				safeConfig[field] = this.maskApiKey(safeConfig[field]);
111 | 			}
112 | 		}
113 | 
114 | 		return safeConfig;
115 | 	}
116 | 
117 | 	/**
118 | 	 * Mask API key for display
119 | 	 * Shows only the last 4 characters for better security
120 | 	 */
121 | 	private maskApiKey(key: string): string {
122 | 		if (key.length <= 4) {
123 | 			return '****';
124 | 		}
125 | 		const visibleChars = 4;
126 | 		const maskedLength = key.length - visibleChars;
127 | 		return (
128 | 			'*'.repeat(Math.min(maskedLength, 12)) +
129 | 			key.substring(key.length - visibleChars)
130 | 		);
131 | 	}
132 | 
133 | 	/**
134 | 	 * Clear cache
135 | 	 */
136 | 	clearCache(): void {
137 | 		this.configCache = null;
138 | 		this.lastReadTime = 0;
139 | 	}
140 | 
141 | 	/**
142 | 	 * Get workspace root path
143 | 	 */
144 | 	private getWorkspaceRoot(): string | undefined {
145 | 		return vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
146 | 	}
147 | }
148 | 
```

--------------------------------------------------------------------------------
/src/progress/cli-progress-factory.js:
--------------------------------------------------------------------------------

```javascript
  1 | import cliProgress from 'cli-progress';
  2 | 
  3 | /**
  4 |  * Default configuration for progress bars
  5 |  * Extracted to avoid duplication and provide single source of truth
  6 |  */
  7 | const DEFAULT_CONFIG = {
  8 | 	clearOnComplete: false,
  9 | 	stopOnComplete: true,
 10 | 	hideCursor: true,
 11 | 	barsize: 40 // Standard terminal width for progress bar
 12 | };
 13 | 
 14 | /**
 15 |  * Available presets for progress bar styling
 16 |  * Makes it easy to see what options are available
 17 |  */
 18 | const PRESETS = {
 19 | 	shades_classic: cliProgress.Presets.shades_classic,
 20 | 	shades_grey: cliProgress.Presets.shades_grey,
 21 | 	rect: cliProgress.Presets.rect,
 22 | 	legacy: cliProgress.Presets.legacy
 23 | };
 24 | 
 25 | /**
 26 |  * Factory class for creating CLI progress bars
 27 |  * Provides a consistent interface for creating both single and multi-bar instances
 28 |  */
 29 | export class ProgressBarFactory {
 30 | 	constructor(defaultOptions = {}, defaultPreset = PRESETS.shades_classic) {
 31 | 		this.defaultOptions = { ...DEFAULT_CONFIG, ...defaultOptions };
 32 | 		this.defaultPreset = defaultPreset;
 33 | 	}
 34 | 
 35 | 	/**
 36 | 	 * Creates a new single progress bar
 37 | 	 * @param {Object} opts - Custom options to override defaults
 38 | 	 * @param {Object} preset - Progress bar preset for styling
 39 | 	 * @returns {cliProgress.SingleBar} Configured single progress bar instance
 40 | 	 */
 41 | 	createSingleBar(opts = {}, preset = null) {
 42 | 		const config = this._mergeConfig(opts);
 43 | 		const barPreset = preset || this.defaultPreset;
 44 | 
 45 | 		return new cliProgress.SingleBar(config, barPreset);
 46 | 	}
 47 | 
 48 | 	/**
 49 | 	 * Creates a new multi-bar container
 50 | 	 * @param {Object} opts - Custom options to override defaults
 51 | 	 * @param {Object} preset - Progress bar preset for styling
 52 | 	 * @returns {cliProgress.MultiBar} Configured multi-bar instance
 53 | 	 */
 54 | 	createMultiBar(opts = {}, preset = null) {
 55 | 		const config = this._mergeConfig(opts);
 56 | 		const barPreset = preset || this.defaultPreset;
 57 | 
 58 | 		return new cliProgress.MultiBar(config, barPreset);
 59 | 	}
 60 | 
 61 | 	/**
 62 | 	 * Merges custom options with defaults
 63 | 	 * @private
 64 | 	 * @param {Object} customOpts - Custom options to merge
 65 | 	 * @returns {Object} Merged configuration
 66 | 	 */
 67 | 	_mergeConfig(customOpts) {
 68 | 		return { ...this.defaultOptions, ...customOpts };
 69 | 	}
 70 | 
 71 | 	/**
 72 | 	 * Updates the default configuration
 73 | 	 * @param {Object} options - New default options
 74 | 	 */
 75 | 	setDefaultOptions(options) {
 76 | 		this.defaultOptions = { ...this.defaultOptions, ...options };
 77 | 	}
 78 | 
 79 | 	/**
 80 | 	 * Updates the default preset
 81 | 	 * @param {Object} preset - New default preset
 82 | 	 */
 83 | 	setDefaultPreset(preset) {
 84 | 		this.defaultPreset = preset;
 85 | 	}
 86 | }
 87 | 
 88 | // Create a default factory instance for backward compatibility
 89 | const defaultFactory = new ProgressBarFactory();
 90 | 
 91 | /**
 92 |  * Legacy function for creating a single progress bar
 93 |  * @deprecated Use ProgressBarFactory.createSingleBar() instead
 94 |  * @param {Object} opts - Progress bar options
 95 |  * @returns {cliProgress.SingleBar} Single progress bar instance
 96 |  */
 97 | export function newSingle(opts = {}) {
 98 | 	return defaultFactory.createSingleBar(opts);
 99 | }
100 | 
101 | /**
102 |  * Legacy function for creating a multi-bar
103 |  * @deprecated Use ProgressBarFactory.createMultiBar() instead
104 |  * @param {Object} opts - Progress bar options
105 |  * @returns {cliProgress.MultiBar} Multi-bar instance
106 |  */
107 | export function newMultiBar(opts = {}) {
108 | 	return defaultFactory.createMultiBar(opts);
109 | }
110 | 
111 | // Export presets for easy access
112 | export { PRESETS };
113 | 
114 | // Export the factory class as default
115 | export default ProgressBarFactory;
116 | 
```

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

```javascript
  1 | /**
  2 |  * tools/add-subtask.js
  3 |  * Tool for adding subtasks to existing tasks
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	handleApiResult,
  9 | 	createErrorResponse,
 10 | 	withNormalizedProjectRoot
 11 | } from './utils.js';
 12 | import { addSubtaskDirect } 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 addSubtask tool with the MCP server
 18 |  * @param {Object} server - FastMCP server instance
 19 |  */
 20 | export function registerAddSubtaskTool(server) {
 21 | 	server.addTool({
 22 | 		name: 'add_subtask',
 23 | 		description: 'Add a subtask to an existing task',
 24 | 		parameters: z.object({
 25 | 			id: z.string().describe('Parent task ID (required)'),
 26 | 			taskId: z
 27 | 				.string()
 28 | 				.optional()
 29 | 				.describe('Existing task ID to convert to subtask'),
 30 | 			title: z
 31 | 				.string()
 32 | 				.optional()
 33 | 				.describe('Title for the new subtask (when creating a new subtask)'),
 34 | 			description: z
 35 | 				.string()
 36 | 				.optional()
 37 | 				.describe('Description for the new subtask'),
 38 | 			details: z
 39 | 				.string()
 40 | 				.optional()
 41 | 				.describe('Implementation details for the new subtask'),
 42 | 			status: z
 43 | 				.string()
 44 | 				.optional()
 45 | 				.describe("Status for the new subtask (default: 'pending')"),
 46 | 			dependencies: z
 47 | 				.string()
 48 | 				.optional()
 49 | 				.describe('Comma-separated list of dependency IDs for the new subtask'),
 50 | 			file: z
 51 | 				.string()
 52 | 				.optional()
 53 | 				.describe(
 54 | 					'Absolute path to the tasks file (default: tasks/tasks.json)'
 55 | 				),
 56 | 			skipGenerate: z
 57 | 				.boolean()
 58 | 				.optional()
 59 | 				.describe('Skip regenerating task files'),
 60 | 			projectRoot: z
 61 | 				.string()
 62 | 				.describe('The directory of the project. Must be an absolute path.'),
 63 | 			tag: z.string().optional().describe('Tag context to operate on')
 64 | 		}),
 65 | 		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
 66 | 			try {
 67 | 				const resolvedTag = resolveTag({
 68 | 					projectRoot: args.projectRoot,
 69 | 					tag: args.tag
 70 | 				});
 71 | 				log.info(`Adding subtask with args: ${JSON.stringify(args)}`);
 72 | 
 73 | 				// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
 74 | 				let tasksJsonPath;
 75 | 				try {
 76 | 					tasksJsonPath = findTasksPath(
 77 | 						{ projectRoot: args.projectRoot, file: args.file },
 78 | 						log
 79 | 					);
 80 | 				} catch (error) {
 81 | 					log.error(`Error finding tasks.json: ${error.message}`);
 82 | 					return createErrorResponse(
 83 | 						`Failed to find tasks.json: ${error.message}`
 84 | 					);
 85 | 				}
 86 | 
 87 | 				const result = await addSubtaskDirect(
 88 | 					{
 89 | 						tasksJsonPath: tasksJsonPath,
 90 | 						id: args.id,
 91 | 						taskId: args.taskId,
 92 | 						title: args.title,
 93 | 						description: args.description,
 94 | 						details: args.details,
 95 | 						status: args.status,
 96 | 						dependencies: args.dependencies,
 97 | 						skipGenerate: args.skipGenerate,
 98 | 						projectRoot: args.projectRoot,
 99 | 						tag: resolvedTag
100 | 					},
101 | 					log,
102 | 					{ session }
103 | 				);
104 | 
105 | 				if (result.success) {
106 | 					log.info(`Subtask added successfully: ${result.data.message}`);
107 | 				} else {
108 | 					log.error(`Failed to add subtask: ${result.error.message}`);
109 | 				}
110 | 
111 | 				return handleApiResult(
112 | 					result,
113 | 					log,
114 | 					'Error adding subtask',
115 | 					undefined,
116 | 					args.projectRoot
117 | 				);
118 | 			} catch (error) {
119 | 				log.error(`Error in addSubtask tool: ${error.message}`);
120 | 				return createErrorResponse(error.message);
121 | 			}
122 | 		})
123 | 	});
124 | }
125 | 
```

--------------------------------------------------------------------------------
/src/provider-registry/index.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Provider Registry - Singleton for managing AI providers
  3 |  *
  4 |  * This module implements a singleton registry that allows dynamic registration
  5 |  * of AI providers at runtime, while maintaining compatibility with the existing
  6 |  * static PROVIDERS object in ai-services-unified.js.
  7 |  */
  8 | 
  9 | // Singleton instance
 10 | let instance = null;
 11 | 
 12 | /**
 13 |  * Provider Registry class - Manages dynamic provider registration
 14 |  */
 15 | class ProviderRegistry {
 16 | 	constructor() {
 17 | 		// Private provider map
 18 | 		this._providers = new Map();
 19 | 
 20 | 		// Flag to track initialization
 21 | 		this._initialized = false;
 22 | 	}
 23 | 
 24 | 	/**
 25 | 	 * Get the singleton instance
 26 | 	 * @returns {ProviderRegistry} The singleton instance
 27 | 	 */
 28 | 	static getInstance() {
 29 | 		if (!instance) {
 30 | 			instance = new ProviderRegistry();
 31 | 		}
 32 | 		return instance;
 33 | 	}
 34 | 
 35 | 	/**
 36 | 	 * Initialize the registry
 37 | 	 * @returns {ProviderRegistry} The singleton instance
 38 | 	 */
 39 | 	initialize() {
 40 | 		if (this._initialized) {
 41 | 			return this;
 42 | 		}
 43 | 
 44 | 		this._initialized = true;
 45 | 		return this;
 46 | 	}
 47 | 
 48 | 	/**
 49 | 	 * Register a provider with the registry
 50 | 	 * @param {string} providerName - The name of the provider
 51 | 	 * @param {object} provider - The provider instance
 52 | 	 * @param {object} options - Additional options for registration
 53 | 	 * @returns {ProviderRegistry} The singleton instance for chaining
 54 | 	 */
 55 | 	registerProvider(providerName, provider, options = {}) {
 56 | 		if (!providerName || typeof providerName !== 'string') {
 57 | 			throw new Error('Provider name must be a non-empty string');
 58 | 		}
 59 | 
 60 | 		if (!provider) {
 61 | 			throw new Error('Provider instance is required');
 62 | 		}
 63 | 
 64 | 		// Validate that provider implements the required interface
 65 | 		if (
 66 | 			typeof provider.generateText !== 'function' ||
 67 | 			typeof provider.streamText !== 'function' ||
 68 | 			typeof provider.generateObject !== 'function'
 69 | 		) {
 70 | 			throw new Error('Provider must implement BaseAIProvider interface');
 71 | 		}
 72 | 
 73 | 		// Add provider to the registry
 74 | 		this._providers.set(providerName, {
 75 | 			instance: provider,
 76 | 			options,
 77 | 			registeredAt: new Date()
 78 | 		});
 79 | 
 80 | 		return this;
 81 | 	}
 82 | 
 83 | 	/**
 84 | 	 * Check if a provider exists in the registry
 85 | 	 * @param {string} providerName - The name of the provider
 86 | 	 * @returns {boolean} True if the provider exists
 87 | 	 */
 88 | 	hasProvider(providerName) {
 89 | 		return this._providers.has(providerName);
 90 | 	}
 91 | 
 92 | 	/**
 93 | 	 * Get a provider from the registry
 94 | 	 * @param {string} providerName - The name of the provider
 95 | 	 * @returns {object|null} The provider instance or null if not found
 96 | 	 */
 97 | 	getProvider(providerName) {
 98 | 		const providerEntry = this._providers.get(providerName);
 99 | 		return providerEntry ? providerEntry.instance : null;
100 | 	}
101 | 
102 | 	/**
103 | 	 * Get all registered providers
104 | 	 * @returns {Map} Map of all registered providers
105 | 	 */
106 | 	getAllProviders() {
107 | 		return new Map(this._providers);
108 | 	}
109 | 
110 | 	/**
111 | 	 * Remove a provider from the registry
112 | 	 * @param {string} providerName - The name of the provider
113 | 	 * @returns {boolean} True if the provider was removed
114 | 	 */
115 | 	unregisterProvider(providerName) {
116 | 		if (this._providers.has(providerName)) {
117 | 			this._providers.delete(providerName);
118 | 			return true;
119 | 		}
120 | 		return false;
121 | 	}
122 | 
123 | 	/**
124 | 	 * Reset the registry (primarily for testing)
125 | 	 */
126 | 	reset() {
127 | 		this._providers.clear();
128 | 		this._initialized = false;
129 | 	}
130 | }
131 | 
132 | ProviderRegistry.getInstance().initialize(); // Ensure singleton is initialized on import
133 | // Export singleton getter
134 | export default ProviderRegistry;
135 | 
```

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

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

--------------------------------------------------------------------------------
/packages/tm-core/src/modules/integration/services/task-retrieval.service.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview Task Retrieval Service
  3 |  * Core service for retrieving tasks with enriched document content
  4 |  * Uses repository for task structure and API for document content
  5 |  */
  6 | 
  7 | import {
  8 | 	ERROR_CODES,
  9 | 	TaskMasterError
 10 | } from '../../../common/errors/task-master-error.js';
 11 | import { getLogger } from '../../../common/logger/factory.js';
 12 | import type { Task } from '../../../common/types/index.js';
 13 | import { AuthManager } from '../../auth/managers/auth-manager.js';
 14 | import { ApiClient } from '../../storage/utils/api-client.js';
 15 | import type { TaskRepository } from '../../tasks/repositories/task-repository.interface.js';
 16 | 
 17 | /**
 18 |  * Response from the get task API endpoint
 19 |  */
 20 | interface GetTaskResponse {
 21 | 	task: Task;
 22 | 	document?: {
 23 | 		id: string;
 24 | 		title: string;
 25 | 		content: string;
 26 | 		createdAt: string;
 27 | 		updatedAt: string;
 28 | 	};
 29 | }
 30 | 
 31 | /**
 32 |  * TaskRetrievalService handles fetching tasks with enriched document content
 33 |  * Uses repository for task structure and API endpoint for document content
 34 |  */
 35 | export class TaskRetrievalService {
 36 | 	private readonly repository: TaskRepository;
 37 | 	private readonly projectId: string;
 38 | 	private readonly apiClient: ApiClient;
 39 | 	private readonly authManager: AuthManager;
 40 | 	private readonly logger = getLogger('TaskRetrievalService');
 41 | 
 42 | 	constructor(
 43 | 		repository: TaskRepository,
 44 | 		projectId: string,
 45 | 		apiClient: ApiClient,
 46 | 		authManager: AuthManager
 47 | 	) {
 48 | 		this.repository = repository;
 49 | 		this.projectId = projectId;
 50 | 		this.apiClient = apiClient;
 51 | 		this.authManager = authManager;
 52 | 	}
 53 | 
 54 | 	/**
 55 | 	 * Get task by ID (UUID or display ID like HAM-123)
 56 | 	 * Uses repository for task structure and API for enriched document content
 57 | 	 * @returns Task with subtasks, dependencies, and document content in details field
 58 | 	 */
 59 | 	async getTask(taskId: string): Promise<Task | null> {
 60 | 		try {
 61 | 			this.authManager.ensureBriefSelected('getTask');
 62 | 
 63 | 			const task = await this.repository.getTask(this.projectId, taskId);
 64 | 
 65 | 			if (!task) {
 66 | 				throw new TaskMasterError(
 67 | 					`Task ${taskId} not found`,
 68 | 					ERROR_CODES.TASK_NOT_FOUND,
 69 | 					{
 70 | 						operation: 'getTask',
 71 | 						taskId,
 72 | 						userMessage: `Task ${taskId} isn't available in the current project.`
 73 | 					}
 74 | 				);
 75 | 			}
 76 | 
 77 | 			// Fetch document content from API and merge into task.details
 78 | 			try {
 79 | 				const url = `/ai/api/v1/tasks/${task.id}`;
 80 | 				const apiResult = await this.apiClient.get<GetTaskResponse>(url);
 81 | 
 82 | 				if (apiResult.document?.content) {
 83 | 					task.details = apiResult.document.content;
 84 | 				}
 85 | 			} catch (error) {
 86 | 				// Document fetch failed - log but don't fail the whole operation
 87 | 				this.logger.debug(
 88 | 					`Could not fetch document content for task ${taskId}: ${error}`
 89 | 				);
 90 | 			}
 91 | 
 92 | 			this.logger.info(`✓ Retrieved task ${taskId}`);
 93 | 			if (task.details) {
 94 | 				this.logger.debug(
 95 | 					`  Document content available (${task.details.length} chars)`
 96 | 				);
 97 | 			}
 98 | 
 99 | 			return task;
100 | 		} catch (error) {
101 | 			// If it's already a TaskMasterError, just add context and re-throw
102 | 			if (error instanceof TaskMasterError) {
103 | 				throw error.withContext({
104 | 					operation: 'getTask',
105 | 					taskId
106 | 				});
107 | 			}
108 | 
109 | 			// For other errors, wrap them
110 | 			const errorMessage =
111 | 				error instanceof Error ? error.message : String(error);
112 | 			throw new TaskMasterError(
113 | 				errorMessage,
114 | 				ERROR_CODES.STORAGE_ERROR,
115 | 				{
116 | 					operation: 'getTask',
117 | 					taskId
118 | 				},
119 | 				error as Error
120 | 			);
121 | 		}
122 | 	}
123 | }
124 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/remove-subtask.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Direct function wrapper for removeSubtask
  3 |  */
  4 | 
  5 | import { removeSubtask } from '../../../../scripts/modules/task-manager.js';
  6 | import {
  7 | 	enableSilentMode,
  8 | 	disableSilentMode
  9 | } from '../../../../scripts/modules/utils.js';
 10 | 
 11 | /**
 12 |  * Remove a subtask from its parent task
 13 |  * @param {Object} args - Function arguments
 14 |  * @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
 15 |  * @param {string} args.id - Subtask ID in format "parentId.subtaskId" (required)
 16 |  * @param {boolean} [args.convert] - Whether to convert the subtask to a standalone task
 17 |  * @param {boolean} [args.skipGenerate] - Skip regenerating task files
 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<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
 22 |  */
 23 | export async function removeSubtaskDirect(args, log) {
 24 | 	// Destructure expected args
 25 | 	const { tasksJsonPath, id, convert, skipGenerate, projectRoot, tag } = args;
 26 | 	try {
 27 | 		// Enable silent mode to prevent console logs from interfering with JSON response
 28 | 		enableSilentMode();
 29 | 
 30 | 		log.info(`Removing subtask with args: ${JSON.stringify(args)}`);
 31 | 
 32 | 		// Check if tasksJsonPath was provided
 33 | 		if (!tasksJsonPath) {
 34 | 			log.error('removeSubtaskDirect called without tasksJsonPath');
 35 | 			disableSilentMode(); // Disable before returning
 36 | 			return {
 37 | 				success: false,
 38 | 				error: {
 39 | 					code: 'MISSING_ARGUMENT',
 40 | 					message: 'tasksJsonPath is required'
 41 | 				}
 42 | 			};
 43 | 		}
 44 | 
 45 | 		if (!id) {
 46 | 			disableSilentMode(); // Disable before returning
 47 | 			return {
 48 | 				success: false,
 49 | 				error: {
 50 | 					code: 'INPUT_VALIDATION_ERROR',
 51 | 					message:
 52 | 						'Subtask ID is required and must be in format "parentId.subtaskId"'
 53 | 				}
 54 | 			};
 55 | 		}
 56 | 
 57 | 		// Validate subtask ID format
 58 | 		if (!id.includes('.')) {
 59 | 			disableSilentMode(); // Disable before returning
 60 | 			return {
 61 | 				success: false,
 62 | 				error: {
 63 | 					code: 'INPUT_VALIDATION_ERROR',
 64 | 					message: `Invalid subtask ID format: ${id}. Expected format: "parentId.subtaskId"`
 65 | 				}
 66 | 			};
 67 | 		}
 68 | 
 69 | 		// Use provided path
 70 | 		const tasksPath = tasksJsonPath;
 71 | 
 72 | 		// Convert convertToTask to a boolean
 73 | 		const convertToTask = convert === true;
 74 | 
 75 | 		// Determine if we should generate files
 76 | 		const generateFiles = !skipGenerate;
 77 | 
 78 | 		log.info(
 79 | 			`Removing subtask ${id} (convertToTask: ${convertToTask}, generateFiles: ${generateFiles})`
 80 | 		);
 81 | 
 82 | 		// Use the provided tasksPath
 83 | 		const result = await removeSubtask(
 84 | 			tasksPath,
 85 | 			id,
 86 | 			convertToTask,
 87 | 			generateFiles,
 88 | 			{
 89 | 				projectRoot,
 90 | 				tag
 91 | 			}
 92 | 		);
 93 | 
 94 | 		// Restore normal logging
 95 | 		disableSilentMode();
 96 | 
 97 | 		if (convertToTask && result) {
 98 | 			// Return info about the converted task
 99 | 			return {
100 | 				success: true,
101 | 				data: {
102 | 					message: `Subtask ${id} successfully converted to task #${result.id}`,
103 | 					task: result
104 | 				}
105 | 			};
106 | 		} else {
107 | 			// Return simple success message for deletion
108 | 			return {
109 | 				success: true,
110 | 				data: {
111 | 					message: `Subtask ${id} successfully removed`
112 | 				}
113 | 			};
114 | 		}
115 | 	} catch (error) {
116 | 		// Ensure silent mode is disabled even if an outer error occurs
117 | 		disableSilentMode();
118 | 
119 | 		log.error(`Error in removeSubtaskDirect: ${error.message}`);
120 | 		return {
121 | 			success: false,
122 | 			error: {
123 | 				code: 'CORE_FUNCTION_ERROR',
124 | 				message: error.message
125 | 			}
126 | 		};
127 | 	}
128 | }
129 | 
```

--------------------------------------------------------------------------------
/src/ui/confirm.js:
--------------------------------------------------------------------------------

```javascript
  1 | import chalk from 'chalk';
  2 | import boxen from 'boxen';
  3 | 
  4 | /**
  5 |  * Confirm removing profile rules (destructive operation)
  6 |  * @param {string[]} profiles - Array of profile names to remove
  7 |  * @returns {Promise<boolean>} - Promise resolving to true if user confirms, false otherwise
  8 |  */
  9 | async function confirmProfilesRemove(profiles) {
 10 | 	const profileList = profiles
 11 | 		.map((b) => b.charAt(0).toUpperCase() + b.slice(1))
 12 | 		.join(', ');
 13 | 	console.log(
 14 | 		boxen(
 15 | 			chalk.yellow(
 16 | 				`WARNING: This will selectively remove Task Master components for: ${profileList}.
 17 | 
 18 | What will be removed:
 19 | • Task Master specific rule files (e.g., cursor_rules.mdc, taskmaster.mdc, etc.)
 20 | • Task Master MCP server configuration (if no other MCP servers exist)
 21 | 
 22 | What will be preserved:
 23 | • Your existing custom rule files
 24 | • Other MCP server configurations
 25 | • The profile directory itself (unless completely empty after removal)
 26 | 
 27 | The .[profile] directory will only be removed if ALL of the following are true:
 28 | • All rules in the directory were Task Master rules (no custom rules)
 29 | • No other files or folders exist in the profile directory
 30 | • The MCP configuration was completely removed (no other servers)
 31 | 
 32 | Are you sure you want to proceed?`
 33 | 			),
 34 | 			{ padding: 1, borderColor: 'yellow', borderStyle: 'round' }
 35 | 		)
 36 | 	);
 37 | 	const inquirer = await import('inquirer');
 38 | 	const { confirm } = await inquirer.default.prompt([
 39 | 		{
 40 | 			type: 'confirm',
 41 | 			name: 'confirm',
 42 | 			message: 'Type y to confirm selective removal, or n to abort:',
 43 | 			default: false
 44 | 		}
 45 | 	]);
 46 | 	return confirm;
 47 | }
 48 | 
 49 | /**
 50 |  * Confirm removing ALL remaining profile rules (extremely critical operation)
 51 |  * @param {string[]} profiles - Array of profile names to remove
 52 |  * @param {string[]} remainingProfiles - Array of profiles that would be left after removal
 53 |  * @returns {Promise<boolean>} - Promise resolving to true if user confirms, false otherwise
 54 |  */
 55 | async function confirmRemoveAllRemainingProfiles(profiles, remainingProfiles) {
 56 | 	const profileList = profiles
 57 | 		.map((p) => p.charAt(0).toUpperCase() + p.slice(1))
 58 | 		.join(', ');
 59 | 
 60 | 	console.log(
 61 | 		boxen(
 62 | 			chalk.red.bold(
 63 | 				`⚠️  CRITICAL WARNING: REMOVING ALL TASK MASTER RULE PROFILES ⚠️\n\n` +
 64 | 					`You are about to remove Task Master components for: ${profileList}\n` +
 65 | 					`This will leave your project with NO Task Master rule profiles remaining!\n\n` +
 66 | 					`What will be removed:\n` +
 67 | 					`• All Task Master specific rule files\n` +
 68 | 					`• Task Master MCP server configurations\n` +
 69 | 					`• Profile directories (only if completely empty after removal)\n\n` +
 70 | 					`What will be preserved:\n` +
 71 | 					`• Your existing custom rule files\n` +
 72 | 					`• Other MCP server configurations\n` +
 73 | 					`• Profile directories with custom content\n\n` +
 74 | 					`This could impact Task Master functionality but will preserve your custom configurations.\n\n` +
 75 | 					`Are you absolutely sure you want to proceed?`
 76 | 			),
 77 | 			{
 78 | 				padding: 1,
 79 | 				borderColor: 'red',
 80 | 				borderStyle: 'double',
 81 | 				title: '🚨 CRITICAL OPERATION',
 82 | 				titleAlignment: 'center'
 83 | 			}
 84 | 		)
 85 | 	);
 86 | 
 87 | 	const inquirer = await import('inquirer');
 88 | 	const { confirm } = await inquirer.default.prompt([
 89 | 		{
 90 | 			type: 'confirm',
 91 | 			name: 'confirm',
 92 | 			message:
 93 | 				'Type y to confirm removing ALL Task Master rule profiles, or n to abort:',
 94 | 			default: false
 95 | 		}
 96 | 	]);
 97 | 	return confirm;
 98 | }
 99 | 
100 | export { confirmProfilesRemove, confirmRemoveAllRemainingProfiles };
101 | 
```

--------------------------------------------------------------------------------
/scripts/modules/task-manager/update-single-task-status.js:
--------------------------------------------------------------------------------

```javascript
  1 | import chalk from 'chalk';
  2 | 
  3 | import { log } from '../utils.js';
  4 | import { isValidTaskStatus } from '../../../src/constants/task-status.js';
  5 | 
  6 | /**
  7 |  * Update the status of a single task
  8 |  * @param {string} tasksPath - Path to the tasks.json file
  9 |  * @param {string} taskIdInput - Task ID to update
 10 |  * @param {string} newStatus - New status
 11 |  * @param {Object} data - Tasks data
 12 |  * @param {boolean} showUi - Whether to show UI elements
 13 |  */
 14 | async function updateSingleTaskStatus(
 15 | 	tasksPath,
 16 | 	taskIdInput,
 17 | 	newStatus,
 18 | 	data,
 19 | 	showUi = true
 20 | ) {
 21 | 	if (!isValidTaskStatus(newStatus)) {
 22 | 		throw new Error(
 23 | 			`Error: Invalid status value: ${newStatus}. Use one of: ${TASK_STATUS_OPTIONS.join(', ')}`
 24 | 		);
 25 | 	}
 26 | 
 27 | 	// Check if it's a subtask (e.g., "1.2")
 28 | 	if (taskIdInput.includes('.')) {
 29 | 		const [parentId, subtaskId] = taskIdInput
 30 | 			.split('.')
 31 | 			.map((id) => parseInt(id, 10));
 32 | 
 33 | 		// Find the parent task
 34 | 		const parentTask = data.tasks.find((t) => t.id === parentId);
 35 | 		if (!parentTask) {
 36 | 			throw new Error(`Parent task ${parentId} not found`);
 37 | 		}
 38 | 
 39 | 		// Find the subtask
 40 | 		if (!parentTask.subtasks) {
 41 | 			throw new Error(`Parent task ${parentId} has no subtasks`);
 42 | 		}
 43 | 
 44 | 		const subtask = parentTask.subtasks.find((st) => st.id === subtaskId);
 45 | 		if (!subtask) {
 46 | 			throw new Error(
 47 | 				`Subtask ${subtaskId} not found in parent task ${parentId}`
 48 | 			);
 49 | 		}
 50 | 
 51 | 		// Update the subtask status
 52 | 		const oldStatus = subtask.status || 'pending';
 53 | 		subtask.status = newStatus;
 54 | 
 55 | 		log(
 56 | 			'info',
 57 | 			`Updated subtask ${parentId}.${subtaskId} status from '${oldStatus}' to '${newStatus}'`
 58 | 		);
 59 | 
 60 | 		// Check if all subtasks are done (if setting to 'done')
 61 | 		if (
 62 | 			newStatus.toLowerCase() === 'done' ||
 63 | 			newStatus.toLowerCase() === 'completed'
 64 | 		) {
 65 | 			const allSubtasksDone = parentTask.subtasks.every(
 66 | 				(st) => st.status === 'done' || st.status === 'completed'
 67 | 			);
 68 | 
 69 | 			// Suggest updating parent task if all subtasks are done
 70 | 			if (
 71 | 				allSubtasksDone &&
 72 | 				parentTask.status !== 'done' &&
 73 | 				parentTask.status !== 'completed'
 74 | 			) {
 75 | 				// Only show suggestion in CLI mode
 76 | 				if (showUi) {
 77 | 					console.log(
 78 | 						chalk.yellow(
 79 | 							`All subtasks of parent task ${parentId} are now marked as done.`
 80 | 						)
 81 | 					);
 82 | 					console.log(
 83 | 						chalk.yellow(
 84 | 							`Consider updating the parent task status with: task-master set-status --id=${parentId} --status=done`
 85 | 						)
 86 | 					);
 87 | 				}
 88 | 			}
 89 | 		}
 90 | 	} else {
 91 | 		// Handle regular task
 92 | 		const taskId = parseInt(taskIdInput, 10);
 93 | 		const task = data.tasks.find((t) => t.id === taskId);
 94 | 
 95 | 		if (!task) {
 96 | 			throw new Error(`Task ${taskId} not found`);
 97 | 		}
 98 | 
 99 | 		// Update the task status
100 | 		const oldStatus = task.status || 'pending';
101 | 		task.status = newStatus;
102 | 
103 | 		log(
104 | 			'info',
105 | 			`Updated task ${taskId} status from '${oldStatus}' to '${newStatus}'`
106 | 		);
107 | 
108 | 		// If marking as done, also mark all subtasks as done
109 | 		if (
110 | 			(newStatus.toLowerCase() === 'done' ||
111 | 				newStatus.toLowerCase() === 'completed') &&
112 | 			task.subtasks &&
113 | 			task.subtasks.length > 0
114 | 		) {
115 | 			const pendingSubtasks = task.subtasks.filter(
116 | 				(st) => st.status !== 'done' && st.status !== 'completed'
117 | 			);
118 | 
119 | 			if (pendingSubtasks.length > 0) {
120 | 				log(
121 | 					'info',
122 | 					`Also marking ${pendingSubtasks.length} subtasks as '${newStatus}'`
123 | 				);
124 | 
125 | 				pendingSubtasks.forEach((subtask) => {
126 | 					subtask.status = newStatus;
127 | 				});
128 | 			}
129 | 		}
130 | 	}
131 | }
132 | 
133 | export default updateSingleTaskStatus;
134 | 
```

--------------------------------------------------------------------------------
/apps/extension/src/components/TaskDetails/useTaskDetails.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { useMemo } from 'react';
  2 | import { useTaskDetails as useTaskDetailsQuery } from '../../webview/hooks/useTaskQueries';
  3 | import type { TaskMasterTask } from '../../webview/types';
  4 | 
  5 | interface TaskFileData {
  6 | 	details?: string;
  7 | 	testStrategy?: string;
  8 | }
  9 | 
 10 | interface UseTaskDetailsProps {
 11 | 	taskId: string;
 12 | 	sendMessage: (message: any) => Promise<any>;
 13 | 	tasks: TaskMasterTask[];
 14 | }
 15 | 
 16 | export const useTaskDetails = ({
 17 | 	taskId,
 18 | 	sendMessage,
 19 | 	tasks
 20 | }: UseTaskDetailsProps) => {
 21 | 	// Parse task ID to determine if it's a subtask (e.g., "13.2")
 22 | 	const { isSubtask, parentId, subtaskIndex, taskIdForFetch } = useMemo(() => {
 23 | 		// Ensure taskId is a string
 24 | 		const taskIdStr = String(taskId);
 25 | 		const parts = taskIdStr.split('.');
 26 | 		if (parts.length === 2) {
 27 | 			return {
 28 | 				isSubtask: true,
 29 | 				parentId: parts[0],
 30 | 				subtaskIndex: parseInt(parts[1]) - 1, // Convert to 0-based index
 31 | 				taskIdForFetch: parts[0] // Always fetch parent task for subtasks
 32 | 			};
 33 | 		}
 34 | 		return {
 35 | 			isSubtask: false,
 36 | 			parentId: taskIdStr,
 37 | 			subtaskIndex: -1,
 38 | 			taskIdForFetch: taskIdStr
 39 | 		};
 40 | 	}, [taskId]);
 41 | 
 42 | 	// Use React Query to fetch full task details
 43 | 	const { data: fullTaskData, error: taskDetailsError } =
 44 | 		useTaskDetailsQuery(taskIdForFetch);
 45 | 
 46 | 	// Find current task from local state for immediate display
 47 | 	const { currentTask, parentTask } = useMemo(() => {
 48 | 		if (isSubtask) {
 49 | 			const parent = tasks.find((t) => t.id === parentId);
 50 | 			if (parent && parent.subtasks && parent.subtasks[subtaskIndex]) {
 51 | 				const subtask = parent.subtasks[subtaskIndex];
 52 | 				return { currentTask: subtask, parentTask: parent };
 53 | 			}
 54 | 		} else {
 55 | 			const task = tasks.find((t) => t.id === String(taskId));
 56 | 			if (task) {
 57 | 				return { currentTask: task, parentTask: null };
 58 | 			}
 59 | 		}
 60 | 		return { currentTask: null, parentTask: null };
 61 | 	}, [taskId, tasks, isSubtask, parentId, subtaskIndex]);
 62 | 
 63 | 	// Merge full task data from React Query with local state
 64 | 	const mergedCurrentTask = useMemo(() => {
 65 | 		if (!currentTask || !fullTaskData) return currentTask;
 66 | 
 67 | 		if (isSubtask && fullTaskData.subtasks) {
 68 | 			// Find the specific subtask in the full data
 69 | 			const subtaskData = fullTaskData.subtasks.find(
 70 | 				(st: any) =>
 71 | 					st.id === currentTask.id || st.id === parseInt(currentTask.id as any)
 72 | 			);
 73 | 			if (subtaskData) {
 74 | 				return { ...currentTask, ...subtaskData };
 75 | 			}
 76 | 		} else if (!isSubtask) {
 77 | 			// Merge parent task data
 78 | 			return { ...currentTask, ...fullTaskData };
 79 | 		}
 80 | 
 81 | 		return currentTask;
 82 | 	}, [currentTask, fullTaskData, isSubtask]);
 83 | 
 84 | 	// Extract task file data
 85 | 	const taskFileData: TaskFileData = useMemo(() => {
 86 | 		if (!mergedCurrentTask) return {};
 87 | 		return {
 88 | 			details: mergedCurrentTask.details || '',
 89 | 			testStrategy: mergedCurrentTask.testStrategy || ''
 90 | 		};
 91 | 	}, [mergedCurrentTask]);
 92 | 
 93 | 	// Get complexity score
 94 | 	const complexity = useMemo(() => {
 95 | 		if (mergedCurrentTask?.complexityScore !== undefined) {
 96 | 			return { score: mergedCurrentTask.complexityScore };
 97 | 		}
 98 | 		return null;
 99 | 	}, [mergedCurrentTask]);
100 | 
101 | 	// Function to refresh data after AI operations
102 | 	const refreshComplexityAfterAI = () => {
103 | 		// React Query will automatically refetch when mutations invalidate the query
104 | 		// No need for manual refresh
105 | 	};
106 | 
107 | 	return {
108 | 		currentTask: mergedCurrentTask,
109 | 		parentTask,
110 | 		isSubtask,
111 | 		taskFileData,
112 | 		taskFileDataError: taskDetailsError ? 'Failed to load task details' : null,
113 | 		complexity,
114 | 		refreshComplexityAfterAI
115 | 	};
116 | };
117 | 
```

--------------------------------------------------------------------------------
/src/prompts/analyze-complexity.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 | 	"id": "analyze-complexity",
 3 | 	"version": "1.0.0",
 4 | 	"description": "Analyze task complexity and generate expansion recommendations",
 5 | 	"metadata": {
 6 | 		"author": "system",
 7 | 		"created": "2024-01-01T00:00:00Z",
 8 | 		"updated": "2024-01-01T00:00:00Z",
 9 | 		"tags": ["analysis", "complexity", "expansion", "recommendations"]
10 | 	},
11 | 	"parameters": {
12 | 		"tasks": {
13 | 			"type": "array",
14 | 			"required": true,
15 | 			"description": "Array of tasks to analyze"
16 | 		},
17 | 		"gatheredContext": {
18 | 			"type": "string",
19 | 			"default": "",
20 | 			"description": "Additional project context"
21 | 		},
22 | 		"threshold": {
23 | 			"type": "number",
24 | 			"default": 5,
25 | 			"min": 1,
26 | 			"max": 10,
27 | 			"description": "Complexity threshold for expansion recommendation"
28 | 		},
29 | 		"useResearch": {
30 | 			"type": "boolean",
31 | 			"default": false,
32 | 			"description": "Use research mode for deeper analysis"
33 | 		},
34 | 		"hasCodebaseAnalysis": {
35 | 			"type": "boolean",
36 | 			"default": false,
37 | 			"description": "Whether codebase analysis is available"
38 | 		},
39 | 		"projectRoot": {
40 | 			"type": "string",
41 | 			"default": "",
42 | 			"description": "Project root path for context"
43 | 		}
44 | 	},
45 | 	"prompts": {
46 | 		"default": {
47 | 			"system": "You are an expert software architect and project manager analyzing task complexity. Your analysis should consider implementation effort, technical challenges, dependencies, and testing requirements.\n\nIMPORTANT: For each task, provide an analysis object with ALL of the following fields:\n- taskId: The ID of the task being analyzed (positive integer)\n- taskTitle: The title of the task\n- complexityScore: A score from 1-10 indicating complexity\n- recommendedSubtasks: Number of subtasks recommended (non-negative integer; 0 if no expansion needed)\n- expansionPrompt: A prompt to guide subtask generation\n- reasoning: Your reasoning for the complexity score\n\nYour response MUST be a JSON object with a single \"complexityAnalysis\" property containing an array of these analysis objects. You may optionally include a \"metadata\" object, but no other top-level properties.",
48 | 			"user": "{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before analyzing task complexity:\n\n1. Use the Glob tool to explore the project structure and understand the codebase size\n2. Use the Grep tool to search for existing implementations related to each task\n3. Use the Read tool to examine key files that would be affected by these tasks\n4. Understand the current implementation state, patterns used, and technical debt\n\nBased on your codebase analysis:\n- Assess complexity based on ACTUAL code that needs to be modified/created\n- Consider existing abstractions and patterns that could simplify implementation\n- Identify tasks that require refactoring vs. greenfield development\n- Factor in dependencies between existing code and new features\n- Provide more accurate subtask recommendations based on real code structure\n\nProject Root: {{projectRoot}}\n\n{{/if}}Analyze the following tasks to determine their complexity (1-10 scale) and recommend the number of subtasks for expansion. Provide a brief reasoning and an initial expansion prompt for each.{{#if useResearch}} Consider current best practices, common implementation patterns, and industry standards in your analysis.{{/if}}\n\nTasks:\n{{{json tasks}}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n"
49 | 		}
50 | 	}
51 | }
52 | 
```

--------------------------------------------------------------------------------
/apps/cli/src/lib/model-management.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview TypeScript bridge for model management functions
  3 |  * Wraps the JavaScript functions with proper TypeScript types
  4 |  * Will remove once we move models.js and config-manager to new structure
  5 |  */
  6 | 
  7 | // @ts-ignore - JavaScript module without types
  8 | import * as configManagerJs from '../../../../scripts/modules/config-manager.js';
  9 | // @ts-ignore - JavaScript module without types
 10 | import * as modelsJs from '../../../../scripts/modules/task-manager/models.js';
 11 | 
 12 | // ========== Types ==========
 13 | 
 14 | export interface ModelCost {
 15 | 	input: number;
 16 | 	output: number;
 17 | }
 18 | 
 19 | export interface ModelData {
 20 | 	id: string;
 21 | 	provider?: string;
 22 | 	swe_score?: number | null;
 23 | 	cost_per_1m_tokens?: ModelCost | null;
 24 | 	allowed_roles?: string[];
 25 | 	max_tokens?: number;
 26 | 	supported?: boolean;
 27 | }
 28 | 
 29 | export interface ModelConfiguration {
 30 | 	provider: string;
 31 | 	modelId: string;
 32 | 	baseURL?: string;
 33 | 	sweScore: number | null;
 34 | 	cost: ModelCost | null;
 35 | 	keyStatus: {
 36 | 		cli: boolean;
 37 | 		mcp: boolean;
 38 | 	};
 39 | }
 40 | 
 41 | export interface ModelConfigurationResponse {
 42 | 	success: boolean;
 43 | 	data?: {
 44 | 		activeModels: {
 45 | 			main: ModelConfiguration;
 46 | 			research: ModelConfiguration;
 47 | 			fallback: ModelConfiguration | null;
 48 | 		};
 49 | 		message: string;
 50 | 	};
 51 | 	error?: {
 52 | 		code: string;
 53 | 		message: string;
 54 | 	};
 55 | }
 56 | 
 57 | export interface AvailableModel {
 58 | 	provider: string;
 59 | 	modelId: string;
 60 | 	sweScore: number | null;
 61 | 	cost: ModelCost | null;
 62 | 	allowedRoles: string[];
 63 | }
 64 | 
 65 | export interface AvailableModelsResponse {
 66 | 	success: boolean;
 67 | 	data?: {
 68 | 		models: AvailableModel[];
 69 | 		message: string;
 70 | 	};
 71 | 	error?: {
 72 | 		code: string;
 73 | 		message: string;
 74 | 	};
 75 | }
 76 | 
 77 | export interface SetModelResponse {
 78 | 	success: boolean;
 79 | 	data?: {
 80 | 		role: string;
 81 | 		provider: string;
 82 | 		modelId: string;
 83 | 		message: string;
 84 | 		warning?: string | null;
 85 | 	};
 86 | 	error?: {
 87 | 		code: string;
 88 | 		message: string;
 89 | 	};
 90 | }
 91 | 
 92 | export interface SetModelOptions {
 93 | 	providerHint?: string;
 94 | 	baseURL?: string;
 95 | 	session?: Record<string, string | undefined>;
 96 | 	mcpLog?: {
 97 | 		info: (...args: unknown[]) => void;
 98 | 		warn: (...args: unknown[]) => void;
 99 | 		error: (...args: unknown[]) => void;
100 | 	};
101 | 	projectRoot: string;
102 | }
103 | 
104 | // ========== Wrapped Functions ==========
105 | 
106 | /**
107 |  * Get the current model configuration
108 |  */
109 | export async function getModelConfiguration(
110 | 	options: SetModelOptions
111 | ): Promise<ModelConfigurationResponse> {
112 | 	return modelsJs.getModelConfiguration(
113 | 		options as any
114 | 	) as Promise<ModelConfigurationResponse>;
115 | }
116 | 
117 | /**
118 |  * Get all available models
119 |  */
120 | export async function getAvailableModelsList(
121 | 	options: SetModelOptions
122 | ): Promise<AvailableModelsResponse> {
123 | 	return modelsJs.getAvailableModelsList(
124 | 		options as any
125 | 	) as Promise<AvailableModelsResponse>;
126 | }
127 | 
128 | /**
129 |  * Set a model for a specific role
130 |  */
131 | export async function setModel(
132 | 	role: 'main' | 'research' | 'fallback',
133 | 	modelId: string,
134 | 	options: SetModelOptions
135 | ): Promise<SetModelResponse> {
136 | 	return modelsJs.setModel(
137 | 		role,
138 | 		modelId,
139 | 		options as any
140 | 	) as Promise<SetModelResponse>;
141 | }
142 | 
143 | /**
144 |  * Get config from config manager
145 |  */
146 | export function getConfig(projectRoot: string): any {
147 | 	return configManagerJs.getConfig(projectRoot);
148 | }
149 | 
150 | /**
151 |  * Write config using config manager
152 |  */
153 | export function writeConfig(config: any, projectRoot: string): boolean {
154 | 	return configManagerJs.writeConfig(config, projectRoot);
155 | }
156 | 
157 | /**
158 |  * Get available models from config manager
159 |  */
160 | export function getAvailableModels(): ModelData[] {
161 | 	return configManagerJs.getAvailableModels() as ModelData[];
162 | }
163 | 
```

--------------------------------------------------------------------------------
/tests/unit/kebab-case-validation.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Kebab case validation tests
  3 |  */
  4 | 
  5 | import { jest } from '@jest/globals';
  6 | import { toKebabCase } from '../../scripts/modules/utils.js';
  7 | 
  8 | // Create a test implementation of detectCamelCaseFlags
  9 | function testDetectCamelCaseFlags(args) {
 10 | 	const camelCaseFlags = [];
 11 | 	for (const arg of args) {
 12 | 		if (arg.startsWith('--')) {
 13 | 			const flagName = arg.split('=')[0].slice(2); // Remove -- and anything after =
 14 | 
 15 | 			// Skip single-word flags - they can't be camelCase
 16 | 			if (!flagName.includes('-') && !/[A-Z]/.test(flagName)) {
 17 | 				continue;
 18 | 			}
 19 | 
 20 | 			// Check for camelCase pattern (lowercase followed by uppercase)
 21 | 			if (/[a-z][A-Z]/.test(flagName)) {
 22 | 				const kebabVersion = toKebabCase(flagName);
 23 | 				if (kebabVersion !== flagName) {
 24 | 					camelCaseFlags.push({
 25 | 						original: flagName,
 26 | 						kebabCase: kebabVersion
 27 | 					});
 28 | 				}
 29 | 			}
 30 | 		}
 31 | 	}
 32 | 	return camelCaseFlags;
 33 | }
 34 | 
 35 | describe('Kebab Case Validation', () => {
 36 | 	describe('toKebabCase', () => {
 37 | 		test('should convert camelCase to kebab-case', () => {
 38 | 			expect(toKebabCase('promptText')).toBe('prompt-text');
 39 | 			expect(toKebabCase('userID')).toBe('user-id');
 40 | 			expect(toKebabCase('numTasks')).toBe('num-tasks');
 41 | 		});
 42 | 
 43 | 		test('should handle already kebab-case strings', () => {
 44 | 			expect(toKebabCase('already-kebab-case')).toBe('already-kebab-case');
 45 | 			expect(toKebabCase('kebab-case')).toBe('kebab-case');
 46 | 		});
 47 | 
 48 | 		test('should handle single words', () => {
 49 | 			expect(toKebabCase('single')).toBe('single');
 50 | 			expect(toKebabCase('file')).toBe('file');
 51 | 		});
 52 | 	});
 53 | 
 54 | 	describe('detectCamelCaseFlags', () => {
 55 | 		test('should properly detect camelCase flags', () => {
 56 | 			const args = [
 57 | 				'node',
 58 | 				'task-master',
 59 | 				'add-task',
 60 | 				'--promptText=test',
 61 | 				'--userID=123'
 62 | 			];
 63 | 			const flags = testDetectCamelCaseFlags(args);
 64 | 
 65 | 			expect(flags).toHaveLength(2);
 66 | 			expect(flags).toContainEqual({
 67 | 				original: 'promptText',
 68 | 				kebabCase: 'prompt-text'
 69 | 			});
 70 | 			expect(flags).toContainEqual({
 71 | 				original: 'userID',
 72 | 				kebabCase: 'user-id'
 73 | 			});
 74 | 		});
 75 | 
 76 | 		test('should not flag kebab-case or lowercase flags', () => {
 77 | 			const args = [
 78 | 				'node',
 79 | 				'task-master',
 80 | 				'add-task',
 81 | 				'--prompt=test',
 82 | 				'--user-id=123'
 83 | 			];
 84 | 			const flags = testDetectCamelCaseFlags(args);
 85 | 
 86 | 			expect(flags).toHaveLength(0);
 87 | 		});
 88 | 
 89 | 		test('should not flag any single-word flags regardless of case', () => {
 90 | 			const args = [
 91 | 				'node',
 92 | 				'task-master',
 93 | 				'add-task',
 94 | 				'--prompt=test', // lowercase
 95 | 				'--PROMPT=test', // uppercase
 96 | 				'--Prompt=test', // mixed case
 97 | 				'--file=test', // lowercase
 98 | 				'--FILE=test', // uppercase
 99 | 				'--File=test' // mixed case
100 | 			];
101 | 			const flags = testDetectCamelCaseFlags(args);
102 | 
103 | 			expect(flags).toHaveLength(0);
104 | 		});
105 | 
106 | 		test('should handle mixed case flags correctly', () => {
107 | 			const args = [
108 | 				'node',
109 | 				'task-master',
110 | 				'add-task',
111 | 				'--prompt=test', // single word, should pass
112 | 				'--promptText=test', // camelCase, should flag
113 | 				'--prompt-text=test', // kebab-case, should pass
114 | 				'--ID=123', // single word, should pass
115 | 				'--userId=123', // camelCase, should flag
116 | 				'--user-id=123' // kebab-case, should pass
117 | 			];
118 | 
119 | 			const flags = testDetectCamelCaseFlags(args);
120 | 
121 | 			expect(flags).toHaveLength(2);
122 | 			expect(flags).toContainEqual({
123 | 				original: 'promptText',
124 | 				kebabCase: 'prompt-text'
125 | 			});
126 | 			expect(flags).toContainEqual({
127 | 				original: 'userId',
128 | 				kebabCase: 'user-id'
129 | 			});
130 | 		});
131 | 	});
132 | });
133 | 
```

--------------------------------------------------------------------------------
/tests/unit/scripts/modules/task-manager/find-next-task.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Tests for the find-next-task.js module
  3 |  */
  4 | import { jest } from '@jest/globals';
  5 | import findNextTask from '../../../../../scripts/modules/task-manager/find-next-task.js';
  6 | 
  7 | describe('findNextTask', () => {
  8 | 	test('should return the highest priority task with all dependencies satisfied', () => {
  9 | 		const tasks = [
 10 | 			{
 11 | 				id: 1,
 12 | 				title: 'Setup Project',
 13 | 				status: 'done',
 14 | 				dependencies: [],
 15 | 				priority: 'high'
 16 | 			},
 17 | 			{
 18 | 				id: 2,
 19 | 				title: 'Implement Core Features',
 20 | 				status: 'pending',
 21 | 				dependencies: [1],
 22 | 				priority: 'high'
 23 | 			},
 24 | 			{
 25 | 				id: 3,
 26 | 				title: 'Create Documentation',
 27 | 				status: 'pending',
 28 | 				dependencies: [1],
 29 | 				priority: 'medium'
 30 | 			},
 31 | 			{
 32 | 				id: 4,
 33 | 				title: 'Deploy Application',
 34 | 				status: 'pending',
 35 | 				dependencies: [2, 3],
 36 | 				priority: 'high'
 37 | 			}
 38 | 		];
 39 | 
 40 | 		const nextTask = findNextTask(tasks);
 41 | 
 42 | 		expect(nextTask).toBeDefined();
 43 | 		expect(nextTask.id).toBe(2);
 44 | 		expect(nextTask.title).toBe('Implement Core Features');
 45 | 	});
 46 | 
 47 | 	test('should prioritize by priority level when dependencies are equal', () => {
 48 | 		const tasks = [
 49 | 			{
 50 | 				id: 1,
 51 | 				title: 'Setup Project',
 52 | 				status: 'done',
 53 | 				dependencies: [],
 54 | 				priority: 'high'
 55 | 			},
 56 | 			{
 57 | 				id: 2,
 58 | 				title: 'Low Priority Task',
 59 | 				status: 'pending',
 60 | 				dependencies: [1],
 61 | 				priority: 'low'
 62 | 			},
 63 | 			{
 64 | 				id: 3,
 65 | 				title: 'Medium Priority Task',
 66 | 				status: 'pending',
 67 | 				dependencies: [1],
 68 | 				priority: 'medium'
 69 | 			},
 70 | 			{
 71 | 				id: 4,
 72 | 				title: 'High Priority Task',
 73 | 				status: 'pending',
 74 | 				dependencies: [1],
 75 | 				priority: 'high'
 76 | 			}
 77 | 		];
 78 | 
 79 | 		const nextTask = findNextTask(tasks);
 80 | 
 81 | 		expect(nextTask.id).toBe(4);
 82 | 		expect(nextTask.priority).toBe('high');
 83 | 	});
 84 | 
 85 | 	test('should return null when all tasks are completed', () => {
 86 | 		const tasks = [
 87 | 			{
 88 | 				id: 1,
 89 | 				title: 'Setup Project',
 90 | 				status: 'done',
 91 | 				dependencies: [],
 92 | 				priority: 'high'
 93 | 			},
 94 | 			{
 95 | 				id: 2,
 96 | 				title: 'Implement Features',
 97 | 				status: 'done',
 98 | 				dependencies: [1],
 99 | 				priority: 'high'
100 | 			}
101 | 		];
102 | 
103 | 		const nextTask = findNextTask(tasks);
104 | 
105 | 		expect(nextTask).toBeNull();
106 | 	});
107 | 
108 | 	test('should return null when all pending tasks have unsatisfied dependencies', () => {
109 | 		const tasks = [
110 | 			{
111 | 				id: 1,
112 | 				title: 'Setup Project',
113 | 				status: 'pending',
114 | 				dependencies: [2],
115 | 				priority: 'high'
116 | 			},
117 | 			{
118 | 				id: 2,
119 | 				title: 'Implement Features',
120 | 				status: 'pending',
121 | 				dependencies: [1],
122 | 				priority: 'high'
123 | 			}
124 | 		];
125 | 
126 | 		const nextTask = findNextTask(tasks);
127 | 
128 | 		expect(nextTask).toBeNull();
129 | 	});
130 | 
131 | 	test('should handle empty tasks array', () => {
132 | 		const nextTask = findNextTask([]);
133 | 
134 | 		expect(nextTask).toBeNull();
135 | 	});
136 | 
137 | 	test('should consider subtask dependencies when finding next task', () => {
138 | 		const tasks = [
139 | 			{
140 | 				id: 1,
141 | 				title: 'Parent Task',
142 | 				status: 'in-progress',
143 | 				dependencies: [],
144 | 				priority: 'high',
145 | 				subtasks: [
146 | 					{
147 | 						id: 1,
148 | 						title: 'Subtask 1',
149 | 						status: 'done',
150 | 						dependencies: []
151 | 					},
152 | 					{
153 | 						id: 2,
154 | 						title: 'Subtask 2',
155 | 						status: 'pending',
156 | 						dependencies: []
157 | 					}
158 | 				]
159 | 			},
160 | 			{
161 | 				id: 2,
162 | 				title: 'Dependent Task',
163 | 				status: 'pending',
164 | 				dependencies: [1],
165 | 				priority: 'high'
166 | 			}
167 | 		];
168 | 
169 | 		const nextTask = findNextTask(tasks);
170 | 
171 | 		// Task 2 should not be returned because Task 1 is not completely done
172 | 		// (it has a pending subtask)
173 | 		expect(nextTask).not.toEqual(expect.objectContaining({ id: 2 }));
174 | 	});
175 | });
176 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/scope-up.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * scope-up.js
  3 |  * Direct function implementation for scoping up task complexity
  4 |  */
  5 | 
  6 | import { scopeUpTask } from '../../../../scripts/modules/task-manager.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 scoping up task complexity with error handling.
 15 |  *
 16 |  * @param {Object} args - Command arguments
 17 |  * @param {string} args.id - Comma-separated list of task IDs to scope up
 18 |  * @param {string} [args.strength='regular'] - Strength level (light, regular, heavy)
 19 |  * @param {string} [args.prompt] - Custom prompt for scoping adjustments
 20 |  * @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
 21 |  * @param {boolean} [args.research=false] - Whether to use research capabilities for scoping
 22 |  * @param {string} args.projectRoot - Project root path
 23 |  * @param {string} [args.tag] - Tag for the task context (optional)
 24 |  * @param {Object} log - Logger object
 25 |  * @param {Object} context - Additional context (session)
 26 |  * @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
 27 |  */
 28 | export async function scopeUpDirect(args, log, context = {}) {
 29 | 	// Destructure expected args
 30 | 	const {
 31 | 		tasksJsonPath,
 32 | 		id,
 33 | 		strength = 'regular',
 34 | 		prompt: customPrompt,
 35 | 		research = false,
 36 | 		projectRoot,
 37 | 		tag
 38 | 	} = args;
 39 | 	const { session } = context; // Destructure session from context
 40 | 
 41 | 	// Enable silent mode to prevent console logs from interfering with JSON response
 42 | 	enableSilentMode();
 43 | 
 44 | 	// Create logger wrapper using the utility
 45 | 	const mcpLog = createLogWrapper(log);
 46 | 
 47 | 	try {
 48 | 		// Check if tasksJsonPath was provided
 49 | 		if (!tasksJsonPath) {
 50 | 			log.error('scopeUpDirect called without tasksJsonPath');
 51 | 			disableSilentMode(); // Disable before returning
 52 | 			return {
 53 | 				success: false,
 54 | 				error: {
 55 | 					code: 'MISSING_ARGUMENT',
 56 | 					message: 'tasksJsonPath is required'
 57 | 				}
 58 | 			};
 59 | 		}
 60 | 
 61 | 		// Check required parameters
 62 | 		if (!id) {
 63 | 			log.error('Missing required parameter: id');
 64 | 			disableSilentMode();
 65 | 			return {
 66 | 				success: false,
 67 | 				error: {
 68 | 					code: 'MISSING_PARAMETER',
 69 | 					message: 'The id parameter is required for scoping up tasks'
 70 | 				}
 71 | 			};
 72 | 		}
 73 | 
 74 | 		// Parse task IDs - convert to numbers as expected by scopeUpTask
 75 | 		const taskIds = id.split(',').map((taskId) => parseInt(taskId.trim(), 10));
 76 | 
 77 | 		log.info(
 78 | 			`Scoping up tasks: ${taskIds.join(', ')}, strength: ${strength}, research: ${research}`
 79 | 		);
 80 | 
 81 | 		// Call the scopeUpTask function
 82 | 		const result = await scopeUpTask(
 83 | 			tasksJsonPath,
 84 | 			taskIds,
 85 | 			strength,
 86 | 			customPrompt,
 87 | 			{
 88 | 				session,
 89 | 				mcpLog,
 90 | 				projectRoot,
 91 | 				commandName: 'scope-up',
 92 | 				outputType: 'mcp',
 93 | 				tag,
 94 | 				research
 95 | 			},
 96 | 			'json' // outputFormat
 97 | 		);
 98 | 
 99 | 		// Restore normal logging
100 | 		disableSilentMode();
101 | 
102 | 		return {
103 | 			success: true,
104 | 			data: {
105 | 				updatedTasks: result.updatedTasks,
106 | 				tasksUpdated: result.updatedTasks.length,
107 | 				message: `Successfully scoped up ${result.updatedTasks.length} task(s)`,
108 | 				telemetryData: result.telemetryData
109 | 			}
110 | 		};
111 | 	} catch (error) {
112 | 		// Make sure to restore normal logging even if there's an error
113 | 		disableSilentMode();
114 | 
115 | 		log.error(`Error in scopeUpDirect: ${error.message}`);
116 | 		return {
117 | 			success: false,
118 | 			error: {
119 | 				code: error.code || 'SCOPE_UP_ERROR',
120 | 				message: error.message
121 | 			}
122 | 		};
123 | 	}
124 | }
125 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/tools/expand-all.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * tools/expand-all.js
  3 |  * Tool for expanding all pending tasks with subtasks
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	handleApiResult,
  9 | 	createErrorResponse,
 10 | 	withNormalizedProjectRoot
 11 | } from './utils.js';
 12 | import { expandAllTasksDirect } from '../core/task-master-core.js';
 13 | import {
 14 | 	findTasksPath,
 15 | 	resolveComplexityReportOutputPath
 16 | } from '../core/utils/path-utils.js';
 17 | import { resolveTag } from '../../../scripts/modules/utils.js';
 18 | 
 19 | /**
 20 |  * Register the expandAll tool with the MCP server
 21 |  * @param {Object} server - FastMCP server instance
 22 |  */
 23 | export function registerExpandAllTool(server) {
 24 | 	server.addTool({
 25 | 		name: 'expand_all',
 26 | 		description:
 27 | 			'Expand all pending tasks into subtasks based on complexity or defaults',
 28 | 		parameters: z.object({
 29 | 			num: z
 30 | 				.string()
 31 | 				.optional()
 32 | 				.describe(
 33 | 					'Target number of subtasks per task (uses complexity/defaults otherwise)'
 34 | 				),
 35 | 			research: z
 36 | 				.boolean()
 37 | 				.optional()
 38 | 				.describe(
 39 | 					'Enable research-backed subtask generation (e.g., using Perplexity)'
 40 | 				),
 41 | 			prompt: z
 42 | 				.string()
 43 | 				.optional()
 44 | 				.describe(
 45 | 					'Additional context to guide subtask generation for all tasks'
 46 | 				),
 47 | 			force: z
 48 | 				.boolean()
 49 | 				.optional()
 50 | 				.describe(
 51 | 					'Force regeneration of subtasks for tasks that already have them'
 52 | 				),
 53 | 			file: z
 54 | 				.string()
 55 | 				.optional()
 56 | 				.describe(
 57 | 					'Absolute path to the tasks file in the /tasks folder inside the project root (default: tasks/tasks.json)'
 58 | 				),
 59 | 			projectRoot: z
 60 | 				.string()
 61 | 				.optional()
 62 | 				.describe(
 63 | 					'Absolute path to the project root directory (derived from session if possible)'
 64 | 				),
 65 | 			tag: z.string().optional().describe('Tag context to operate on')
 66 | 		}),
 67 | 		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
 68 | 			try {
 69 | 				log.info(
 70 | 					`Tool expand_all execution started with args: ${JSON.stringify(args)}`
 71 | 				);
 72 | 
 73 | 				const resolvedTag = resolveTag({
 74 | 					projectRoot: args.projectRoot,
 75 | 					tag: args.tag
 76 | 				});
 77 | 				let tasksJsonPath;
 78 | 				try {
 79 | 					tasksJsonPath = findTasksPath(
 80 | 						{ projectRoot: args.projectRoot, file: args.file },
 81 | 						log
 82 | 					);
 83 | 					log.info(`Resolved tasks.json path: ${tasksJsonPath}`);
 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 | 				// Resolve complexity report path to use recommendations from analyze-complexity
 92 | 				const complexityReportPath = resolveComplexityReportOutputPath(
 93 | 					null,
 94 | 					{ projectRoot: args.projectRoot, tag: resolvedTag },
 95 | 					log
 96 | 				);
 97 | 				log.info(`Using complexity report path: ${complexityReportPath}`);
 98 | 
 99 | 				const result = await expandAllTasksDirect(
100 | 					{
101 | 						tasksJsonPath: tasksJsonPath,
102 | 						num: args.num,
103 | 						research: args.research,
104 | 						prompt: args.prompt,
105 | 						force: args.force,
106 | 						projectRoot: args.projectRoot,
107 | 						tag: resolvedTag,
108 | 						complexityReportPath
109 | 					},
110 | 					log,
111 | 					{ session }
112 | 				);
113 | 
114 | 				return handleApiResult(
115 | 					result,
116 | 					log,
117 | 					'Error expanding all tasks',
118 | 					undefined,
119 | 					args.projectRoot
120 | 				);
121 | 			} catch (error) {
122 | 				log.error(
123 | 					`Unexpected error in expand_all tool execute: ${error.message}`
124 | 				);
125 | 				if (error.stack) {
126 | 					log.error(error.stack);
127 | 				}
128 | 				return createErrorResponse(
129 | 					`An unexpected error occurred: ${error.message}`
130 | 				);
131 | 			}
132 | 		})
133 | 	});
134 | }
135 | 
```

--------------------------------------------------------------------------------
/packages/ai-sdk-provider-grok-cli/src/json-extractor.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Extract JSON from AI's response using a tolerant parser.
  3 |  *
  4 |  * The function removes common wrappers such as markdown fences or variable
  5 |  * declarations and then attempts to parse the remaining text with
  6 |  * `jsonc-parser`.  If valid JSON (or JSONC) can be parsed, it is returned as a
  7 |  * string via `JSON.stringify`.  Otherwise the original text is returned.
  8 |  *
  9 |  * @param text - Raw text which may contain JSON
 10 |  * @returns A valid JSON string if extraction succeeds, otherwise the original text
 11 |  */
 12 | import { parse, type ParseError } from 'jsonc-parser';
 13 | 
 14 | export function extractJson(text: string): string {
 15 | 	let content = text.trim();
 16 | 
 17 | 	// Strip ```json or ``` fences
 18 | 	const fenceMatch = /```(?:json)?\s*([\s\S]*?)\s*```/i.exec(content);
 19 | 	if (fenceMatch) {
 20 | 		content = fenceMatch[1];
 21 | 	}
 22 | 
 23 | 	// Strip variable declarations like `const foo =` or `let foo =`
 24 | 	const varMatch = /^\s*(?:const|let|var)\s+\w+\s*=\s*([\s\S]*)/i.exec(content);
 25 | 	if (varMatch) {
 26 | 		content = varMatch[1];
 27 | 		// Remove trailing semicolon if present
 28 | 		if (content.trim().endsWith(';')) {
 29 | 			content = content.trim().slice(0, -1);
 30 | 		}
 31 | 	}
 32 | 
 33 | 	// Find the first opening bracket
 34 | 	const firstObj = content.indexOf('{');
 35 | 	const firstArr = content.indexOf('[');
 36 | 	if (firstObj === -1 && firstArr === -1) {
 37 | 		return text;
 38 | 	}
 39 | 	const start =
 40 | 		firstArr === -1
 41 | 			? firstObj
 42 | 			: firstObj === -1
 43 | 				? firstArr
 44 | 				: Math.min(firstObj, firstArr);
 45 | 	content = content.slice(start);
 46 | 
 47 | 	// Try to parse the entire string with jsonc-parser
 48 | 	const tryParse = (value: string): string | undefined => {
 49 | 		const errors: ParseError[] = [];
 50 | 		try {
 51 | 			const result = parse(value, errors, { allowTrailingComma: true });
 52 | 			if (errors.length === 0) {
 53 | 				return JSON.stringify(result, null, 2);
 54 | 			}
 55 | 		} catch {
 56 | 			// ignore
 57 | 		}
 58 | 		return undefined;
 59 | 	};
 60 | 
 61 | 	const parsed = tryParse(content);
 62 | 	if (parsed !== undefined) {
 63 | 		return parsed;
 64 | 	}
 65 | 
 66 | 	// If parsing the full string failed, use a more efficient approach
 67 | 	// to find valid JSON boundaries
 68 | 	const openChar = content[0];
 69 | 	const closeChar = openChar === '{' ? '}' : ']';
 70 | 
 71 | 	// Find all potential closing positions by tracking nesting depth
 72 | 	const closingPositions: number[] = [];
 73 | 	let depth = 0;
 74 | 	let inString = false;
 75 | 	let escapeNext = false;
 76 | 
 77 | 	for (let i = 0; i < content.length; i++) {
 78 | 		const char = content[i];
 79 | 
 80 | 		if (escapeNext) {
 81 | 			escapeNext = false;
 82 | 			continue;
 83 | 		}
 84 | 
 85 | 		if (char === '\\') {
 86 | 			escapeNext = true;
 87 | 			continue;
 88 | 		}
 89 | 
 90 | 		if (char === '"' && !inString) {
 91 | 			inString = true;
 92 | 			continue;
 93 | 		}
 94 | 
 95 | 		if (char === '"' && inString) {
 96 | 			inString = false;
 97 | 			continue;
 98 | 		}
 99 | 
100 | 		// Skip content inside strings
101 | 		if (inString) continue;
102 | 
103 | 		if (char === openChar) {
104 | 			depth++;
105 | 		} else if (char === closeChar) {
106 | 			depth--;
107 | 			if (depth === 0) {
108 | 				closingPositions.push(i + 1);
109 | 			}
110 | 		}
111 | 	}
112 | 
113 | 	// Try parsing at each valid closing position, starting from the end
114 | 	for (let i = closingPositions.length - 1; i >= 0; i--) {
115 | 		const attempt = tryParse(content.slice(0, closingPositions[i]));
116 | 		if (attempt !== undefined) {
117 | 			return attempt;
118 | 		}
119 | 	}
120 | 
121 | 	// As a final fallback, try the original character-by-character approach
122 | 	// but only for the last 1000 characters to limit performance impact
123 | 	const searchStart = Math.max(0, content.length - 1000);
124 | 	for (let end = content.length - 1; end > searchStart; end--) {
125 | 		const attempt = tryParse(content.slice(0, end));
126 | 		if (attempt !== undefined) {
127 | 			return attempt;
128 | 		}
129 | 	}
130 | 
131 | 	return text;
132 | }
133 | 
```

--------------------------------------------------------------------------------
/packages/ai-sdk-provider-grok-cli/src/grok-cli-provider.test.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * Tests for Grok CLI provider
  3 |  */
  4 | 
  5 | import { NoSuchModelError } from '@ai-sdk/provider';
  6 | import { beforeEach, describe, expect, it, vi } from 'vitest';
  7 | import { GrokCliLanguageModel } from './grok-cli-language-model.js';
  8 | import { createGrokCli, grokCli } from './grok-cli-provider.js';
  9 | 
 10 | // Mock the GrokCliLanguageModel
 11 | vi.mock('./grok-cli-language-model.js', () => ({
 12 | 	GrokCliLanguageModel: vi.fn().mockImplementation((options) => ({
 13 | 		modelId: options.id,
 14 | 		settings: options.settings,
 15 | 		provider: 'grok-cli'
 16 | 	}))
 17 | }));
 18 | 
 19 | describe('createGrokCli', () => {
 20 | 	beforeEach(() => {
 21 | 		vi.clearAllMocks();
 22 | 	});
 23 | 
 24 | 	it('should create a provider with default settings', () => {
 25 | 		const provider = createGrokCli();
 26 | 		expect(typeof provider).toBe('function');
 27 | 		expect(typeof provider.languageModel).toBe('function');
 28 | 		expect(typeof provider.chat).toBe('function');
 29 | 		expect(typeof provider.textEmbeddingModel).toBe('function');
 30 | 		expect(typeof provider.imageModel).toBe('function');
 31 | 	});
 32 | 
 33 | 	it('should create a provider with custom default settings', () => {
 34 | 		const defaultSettings = {
 35 | 			timeout: 5000,
 36 | 			workingDirectory: '/custom/path'
 37 | 		};
 38 | 		const provider = createGrokCli({ defaultSettings });
 39 | 
 40 | 		const model = provider('grok-2-mini');
 41 | 
 42 | 		expect(GrokCliLanguageModel).toHaveBeenCalledWith({
 43 | 			id: 'grok-2-mini',
 44 | 			settings: defaultSettings
 45 | 		});
 46 | 	});
 47 | 
 48 | 	it('should create language models with merged settings', () => {
 49 | 		const defaultSettings = { timeout: 5000 };
 50 | 		const provider = createGrokCli({ defaultSettings });
 51 | 
 52 | 		const modelSettings = { apiKey: 'test-key' };
 53 | 		const model = provider('grok-2', modelSettings);
 54 | 
 55 | 		expect(GrokCliLanguageModel).toHaveBeenCalledWith({
 56 | 			id: 'grok-2',
 57 | 			settings: { timeout: 5000, apiKey: 'test-key' }
 58 | 		});
 59 | 	});
 60 | 
 61 | 	it('should create models via languageModel method', () => {
 62 | 		const provider = createGrokCli();
 63 | 		const model = provider.languageModel('grok-2-mini', { timeout: 1000 });
 64 | 
 65 | 		expect(GrokCliLanguageModel).toHaveBeenCalledWith({
 66 | 			id: 'grok-2-mini',
 67 | 			settings: { timeout: 1000 }
 68 | 		});
 69 | 	});
 70 | 
 71 | 	it('should create models via chat method (alias)', () => {
 72 | 		const provider = createGrokCli();
 73 | 		const model = provider.chat('grok-2');
 74 | 
 75 | 		expect(GrokCliLanguageModel).toHaveBeenCalledWith({
 76 | 			id: 'grok-2',
 77 | 			settings: {}
 78 | 		});
 79 | 	});
 80 | 
 81 | 	it('should throw error when called with new keyword', () => {
 82 | 		const provider = createGrokCli();
 83 | 		expect(() => {
 84 | 			// @ts-expect-error - intentionally testing invalid usage
 85 | 			new provider('grok-2');
 86 | 		}).toThrow(
 87 | 			'The Grok CLI model function cannot be called with the new keyword.'
 88 | 		);
 89 | 	});
 90 | 
 91 | 	it('should throw NoSuchModelError for textEmbeddingModel', () => {
 92 | 		const provider = createGrokCli();
 93 | 		expect(() => {
 94 | 			provider.textEmbeddingModel('test-model');
 95 | 		}).toThrow(NoSuchModelError);
 96 | 	});
 97 | 
 98 | 	it('should throw NoSuchModelError for imageModel', () => {
 99 | 		const provider = createGrokCli();
100 | 		expect(() => {
101 | 			provider.imageModel('test-model');
102 | 		}).toThrow(NoSuchModelError);
103 | 	});
104 | });
105 | 
106 | describe('default grokCli provider', () => {
107 | 	it('should be a pre-configured provider instance', () => {
108 | 		expect(typeof grokCli).toBe('function');
109 | 		expect(typeof grokCli.languageModel).toBe('function');
110 | 		expect(typeof grokCli.chat).toBe('function');
111 | 	});
112 | 
113 | 	it('should create models with default configuration', () => {
114 | 		const model = grokCli('grok-2-mini');
115 | 
116 | 		expect(GrokCliLanguageModel).toHaveBeenCalledWith({
117 | 			id: 'grok-2-mini',
118 | 			settings: {}
119 | 		});
120 | 	});
121 | });
122 | 
```

--------------------------------------------------------------------------------
/tests/unit/profiles/opencode-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 | describe('OpenCode Profile Integration', () => {
  7 | 	let tempDir;
  8 | 
  9 | 	beforeEach(() => {
 10 | 		jest.clearAllMocks();
 11 | 
 12 | 		// Create a temporary directory for testing
 13 | 		tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'task-master-test-'));
 14 | 
 15 | 		// Spy on fs methods
 16 | 		jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
 17 | 		jest.spyOn(fs, 'readFileSync').mockImplementation((filePath) => {
 18 | 			if (filePath.toString().includes('AGENTS.md')) {
 19 | 				return 'Sample AGENTS.md content for OpenCode integration';
 20 | 			}
 21 | 			if (filePath.toString().includes('opencode.json')) {
 22 | 				return JSON.stringify({ mcpServers: {} }, null, 2);
 23 | 			}
 24 | 			return '{}';
 25 | 		});
 26 | 		jest.spyOn(fs, 'existsSync').mockImplementation(() => false);
 27 | 		jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {});
 28 | 	});
 29 | 
 30 | 	afterEach(() => {
 31 | 		// Clean up the temporary directory
 32 | 		try {
 33 | 			fs.rmSync(tempDir, { recursive: true, force: true });
 34 | 		} catch (err) {
 35 | 			console.error(`Error cleaning up: ${err.message}`);
 36 | 		}
 37 | 	});
 38 | 
 39 | 	// Test function that simulates the OpenCode profile file copying behavior
 40 | 	function mockCreateOpenCodeStructure() {
 41 | 		// OpenCode profile copies AGENTS.md to AGENTS.md in project root (same name)
 42 | 		const sourceContent = 'Sample AGENTS.md content for OpenCode integration';
 43 | 		fs.writeFileSync(path.join(tempDir, 'AGENTS.md'), sourceContent);
 44 | 
 45 | 		// OpenCode profile creates opencode.json config file
 46 | 		const configContent = JSON.stringify({ mcpServers: {} }, null, 2);
 47 | 		fs.writeFileSync(path.join(tempDir, 'opencode.json'), configContent);
 48 | 	}
 49 | 
 50 | 	test('creates AGENTS.md file in project root', () => {
 51 | 		// Act
 52 | 		mockCreateOpenCodeStructure();
 53 | 
 54 | 		// Assert
 55 | 		expect(fs.writeFileSync).toHaveBeenCalledWith(
 56 | 			path.join(tempDir, 'AGENTS.md'),
 57 | 			'Sample AGENTS.md content for OpenCode integration'
 58 | 		);
 59 | 	});
 60 | 
 61 | 	test('creates opencode.json config file in project root', () => {
 62 | 		// Act
 63 | 		mockCreateOpenCodeStructure();
 64 | 
 65 | 		// Assert
 66 | 		expect(fs.writeFileSync).toHaveBeenCalledWith(
 67 | 			path.join(tempDir, 'opencode.json'),
 68 | 			JSON.stringify({ mcpServers: {} }, null, 2)
 69 | 		);
 70 | 	});
 71 | 
 72 | 	test('does not create any profile directories', () => {
 73 | 		// Act
 74 | 		mockCreateOpenCodeStructure();
 75 | 
 76 | 		// Assert - OpenCode profile should not create any directories
 77 | 		// Only the temp directory creation calls should exist
 78 | 		const mkdirCalls = fs.mkdirSync.mock.calls.filter(
 79 | 			(call) => !call[0].includes('task-master-test-')
 80 | 		);
 81 | 		expect(mkdirCalls).toHaveLength(0);
 82 | 	});
 83 | 
 84 | 	test('handles transformation of MCP config format', () => {
 85 | 		// This test simulates the transformation behavior that would happen in onPostConvert
 86 | 		const standardMcpConfig = {
 87 | 			mcpServers: {
 88 | 				'taskmaster-ai': {
 89 | 					command: 'node',
 90 | 					args: ['path/to/server.js'],
 91 | 					env: {
 92 | 						API_KEY: 'test-key'
 93 | 					}
 94 | 				}
 95 | 			}
 96 | 		};
 97 | 
 98 | 		const expectedOpenCodeConfig = {
 99 | 			$schema: 'https://opencode.ai/config.json',
100 | 			mcp: {
101 | 				'taskmaster-ai': {
102 | 					type: 'local',
103 | 					command: ['node', 'path/to/server.js'],
104 | 					enabled: true,
105 | 					environment: {
106 | 						API_KEY: 'test-key'
107 | 					}
108 | 				}
109 | 			}
110 | 		};
111 | 
112 | 		// Mock the transformation behavior
113 | 		fs.writeFileSync(
114 | 			path.join(tempDir, 'opencode.json'),
115 | 			JSON.stringify(expectedOpenCodeConfig, null, 2)
116 | 		);
117 | 
118 | 		expect(fs.writeFileSync).toHaveBeenCalledWith(
119 | 			path.join(tempDir, 'opencode.json'),
120 | 			JSON.stringify(expectedOpenCodeConfig, null, 2)
121 | 		);
122 | 	});
123 | });
124 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/scope-down.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * scope-down.js
  3 |  * Direct function implementation for scoping down task complexity
  4 |  */
  5 | 
  6 | import { scopeDownTask } from '../../../../scripts/modules/task-manager.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 scoping down task complexity with error handling.
 15 |  *
 16 |  * @param {Object} args - Command arguments
 17 |  * @param {string} args.id - Comma-separated list of task IDs to scope down
 18 |  * @param {string} [args.strength='regular'] - Strength level (light, regular, heavy)
 19 |  * @param {string} [args.prompt] - Custom prompt for scoping adjustments
 20 |  * @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
 21 |  * @param {boolean} [args.research=false] - Whether to use research capabilities for scoping
 22 |  * @param {string} args.projectRoot - Project root path
 23 |  * @param {string} [args.tag] - Tag for the task context (optional)
 24 |  * @param {Object} log - Logger object
 25 |  * @param {Object} context - Additional context (session)
 26 |  * @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
 27 |  */
 28 | export async function scopeDownDirect(args, log, context = {}) {
 29 | 	// Destructure expected args
 30 | 	const {
 31 | 		tasksJsonPath,
 32 | 		id,
 33 | 		strength = 'regular',
 34 | 		prompt: customPrompt,
 35 | 		research = false,
 36 | 		projectRoot,
 37 | 		tag
 38 | 	} = args;
 39 | 	const { session } = context; // Destructure session from context
 40 | 
 41 | 	// Enable silent mode to prevent console logs from interfering with JSON response
 42 | 	enableSilentMode();
 43 | 
 44 | 	// Create logger wrapper using the utility
 45 | 	const mcpLog = createLogWrapper(log);
 46 | 
 47 | 	try {
 48 | 		// Check if tasksJsonPath was provided
 49 | 		if (!tasksJsonPath) {
 50 | 			log.error('scopeDownDirect called without tasksJsonPath');
 51 | 			disableSilentMode(); // Disable before returning
 52 | 			return {
 53 | 				success: false,
 54 | 				error: {
 55 | 					code: 'MISSING_ARGUMENT',
 56 | 					message: 'tasksJsonPath is required'
 57 | 				}
 58 | 			};
 59 | 		}
 60 | 
 61 | 		// Check required parameters
 62 | 		if (!id) {
 63 | 			log.error('Missing required parameter: id');
 64 | 			disableSilentMode();
 65 | 			return {
 66 | 				success: false,
 67 | 				error: {
 68 | 					code: 'MISSING_PARAMETER',
 69 | 					message: 'The id parameter is required for scoping down tasks'
 70 | 				}
 71 | 			};
 72 | 		}
 73 | 
 74 | 		// Parse task IDs - convert to numbers as expected by scopeDownTask
 75 | 		const taskIds = id.split(',').map((taskId) => parseInt(taskId.trim(), 10));
 76 | 
 77 | 		log.info(
 78 | 			`Scoping down tasks: ${taskIds.join(', ')}, strength: ${strength}, research: ${research}`
 79 | 		);
 80 | 
 81 | 		// Call the scopeDownTask function
 82 | 		const result = await scopeDownTask(
 83 | 			tasksJsonPath,
 84 | 			taskIds,
 85 | 			strength,
 86 | 			customPrompt,
 87 | 			{
 88 | 				session,
 89 | 				mcpLog,
 90 | 				projectRoot,
 91 | 				commandName: 'scope-down',
 92 | 				outputType: 'mcp',
 93 | 				tag,
 94 | 				research
 95 | 			},
 96 | 			'json' // outputFormat
 97 | 		);
 98 | 
 99 | 		// Restore normal logging
100 | 		disableSilentMode();
101 | 
102 | 		return {
103 | 			success: true,
104 | 			data: {
105 | 				updatedTasks: result.updatedTasks,
106 | 				tasksUpdated: result.updatedTasks.length,
107 | 				message: `Successfully scoped down ${result.updatedTasks.length} task(s)`,
108 | 				telemetryData: result.telemetryData
109 | 			}
110 | 		};
111 | 	} catch (error) {
112 | 		// Make sure to restore normal logging even if there's an error
113 | 		disableSilentMode();
114 | 
115 | 		log.error(`Error in scopeDownDirect: ${error.message}`);
116 | 		return {
117 | 			success: false,
118 | 			error: {
119 | 				code: error.code || 'SCOPE_DOWN_ERROR',
120 | 				message: error.message
121 | 			}
122 | 		};
123 | 	}
124 | }
125 | 
```

--------------------------------------------------------------------------------
/packages/claude-code-plugin/commands/help.md:
--------------------------------------------------------------------------------

```markdown
 1 | Show help for Task Master AI commands.
 2 | 
 3 | Arguments: $ARGUMENTS
 4 | 
 5 | Display help for Task Master commands. If arguments provided, show specific command help.
 6 | 
 7 | ## Task Master AI Command Help
 8 | 
 9 | ### Quick Navigation
10 | 
11 | Type `/taskmaster:` and use tab completion to explore all commands.
12 | 
13 | ### Command Categories
14 | 
15 | #### 🚀 Setup & Installation
16 | - `/taskmaster:install-taskmaster` - Comprehensive installation guide
17 | - `/taskmaster:quick-install-taskmaster` - One-line global install
18 | 
19 | #### 📋 Project Setup
20 | - `/taskmaster:init-project` - Initialize new project
21 | - `/taskmaster:init-project-quick` - Quick setup with auto-confirm
22 | - `/taskmaster:view-models` - View AI configuration
23 | - `/taskmaster:setup-models` - Configure AI providers
24 | 
25 | #### 🎯 Task Generation
26 | - `/taskmaster:parse-prd` - Generate tasks from PRD
27 | - `/taskmaster:parse-prd-with-research` - Enhanced parsing
28 | - `/taskmaster:generate-tasks` - Create task files
29 | 
30 | #### 📝 Task Management
31 | - `/taskmaster:list-tasks` - List all tasks
32 | - `/taskmaster:list-tasks-by-status` - List tasks filtered by status
33 | - `/taskmaster:list-tasks-with-subtasks` - List tasks with subtasks
34 | - `/taskmaster:show-task` - Display task details
35 | - `/taskmaster:add-task` - Create new task
36 | - `/taskmaster:update-task` - Update single task
37 | - `/taskmaster:update-tasks-from-id` - Update multiple tasks
38 | - `/taskmaster:next-task` - Get next task recommendation
39 | 
40 | #### 🔄 Status Management
41 | - `/taskmaster:to-pending` - Set task to pending
42 | - `/taskmaster:to-in-progress` - Set task to in-progress
43 | - `/taskmaster:to-done` - Set task to done
44 | - `/taskmaster:to-review` - Set task to review
45 | - `/taskmaster:to-deferred` - Set task to deferred
46 | - `/taskmaster:to-cancelled` - Set task to cancelled
47 | 
48 | #### 🔍 Analysis & Breakdown
49 | - `/taskmaster:analyze-complexity` - Analyze task complexity
50 | - `/taskmaster:complexity-report` - View complexity report
51 | - `/taskmaster:expand-task` - Break down complex task
52 | - `/taskmaster:expand-all-tasks` - Expand all eligible tasks
53 | 
54 | #### 🔗 Dependencies
55 | - `/taskmaster:add-dependency` - Add task dependency
56 | - `/taskmaster:remove-dependency` - Remove dependency
57 | - `/taskmaster:validate-dependencies` - Check for issues
58 | - `/taskmaster:fix-dependencies` - Auto-fix dependency issues
59 | 
60 | #### 📦 Subtasks
61 | - `/taskmaster:add-subtask` - Add subtask to task
62 | - `/taskmaster:convert-task-to-subtask` - Convert task to subtask
63 | - `/taskmaster:remove-subtask` - Remove subtask
64 | - `/taskmaster:remove-subtasks` - Clear specific task subtasks
65 | - `/taskmaster:remove-all-subtasks` - Clear all subtasks
66 | 
67 | #### 🗑️ Task Removal
68 | - `/taskmaster:remove-task` - Remove task permanently
69 | 
70 | #### 🤖 Workflows
71 | - `/taskmaster:smart-workflow` - Intelligent workflows
72 | - `/taskmaster:command-pipeline` - Command chaining
73 | - `/taskmaster:auto-implement-tasks` - Auto-implementation
74 | 
75 | #### 📊 Utilities
76 | - `/taskmaster:analyze-project` - Project analysis
77 | - `/taskmaster:project-status` - Project dashboard
78 | - `/taskmaster:sync-readme` - Sync README with tasks
79 | - `/taskmaster:learn` - Interactive learning
80 | - `/taskmaster:tm-main` - Main Task Master interface
81 | 
82 | ### Quick Start Examples
83 | 
84 | ```
85 | /taskmaster:list-tasks
86 | /taskmaster:show-task 1.2
87 | /taskmaster:add-task
88 | /taskmaster:next-task
89 | ```
90 | 
91 | ### Getting Started
92 | 
93 | 1. Install: `/taskmaster:quick-install-taskmaster`
94 | 2. Initialize: `/taskmaster:init-project-quick`
95 | 3. Learn: `/taskmaster:learn`
96 | 4. Work: `/taskmaster:smart-workflow`
97 | 
98 | For detailed command info, run the specific command with `--help` or check command documentation.
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/list-tags.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * list-tags.js
  3 |  * Direct function implementation for listing all tags
  4 |  */
  5 | 
  6 | import { tags } 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 listing all tags with error handling.
 15 |  *
 16 |  * @param {Object} args - Command arguments
 17 |  * @param {boolean} [args.showMetadata=false] - Whether to include metadata in the output
 18 |  * @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
 19 |  * @param {string} [args.projectRoot] - Project root path
 20 |  * @param {Object} log - Logger object
 21 |  * @param {Object} context - Additional context (session)
 22 |  * @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
 23 |  */
 24 | export async function listTagsDirect(args, log, context = {}) {
 25 | 	// Destructure expected args
 26 | 	const { tasksJsonPath, showMetadata = false, projectRoot } = args;
 27 | 	const { session } = context;
 28 | 
 29 | 	// Enable silent mode to prevent console logs from interfering with JSON response
 30 | 	enableSilentMode();
 31 | 
 32 | 	// Create logger wrapper using the utility
 33 | 	const mcpLog = createLogWrapper(log);
 34 | 
 35 | 	try {
 36 | 		// Check if tasksJsonPath was provided
 37 | 		if (!tasksJsonPath) {
 38 | 			log.error('listTagsDirect called without tasksJsonPath');
 39 | 			disableSilentMode();
 40 | 			return {
 41 | 				success: false,
 42 | 				error: {
 43 | 					code: 'MISSING_ARGUMENT',
 44 | 					message: 'tasksJsonPath is required'
 45 | 				}
 46 | 			};
 47 | 		}
 48 | 
 49 | 		log.info('Listing all tags');
 50 | 
 51 | 		// Prepare options
 52 | 		const options = {
 53 | 			showMetadata
 54 | 		};
 55 | 
 56 | 		// Call the tags function
 57 | 		const result = await tags(
 58 | 			tasksJsonPath,
 59 | 			options,
 60 | 			{
 61 | 				session,
 62 | 				mcpLog,
 63 | 				projectRoot
 64 | 			},
 65 | 			'json' // outputFormat - use 'json' to suppress CLI UI
 66 | 		);
 67 | 
 68 | 		// Transform the result to remove full task data and provide summary info
 69 | 		const tagsSummary = result.tags.map((tag) => {
 70 | 			const tasks = tag.tasks || [];
 71 | 
 72 | 			// Calculate status breakdown
 73 | 			const statusBreakdown = tasks.reduce((acc, task) => {
 74 | 				const status = task.status || 'pending';
 75 | 				acc[status] = (acc[status] || 0) + 1;
 76 | 				return acc;
 77 | 			}, {});
 78 | 
 79 | 			// Calculate subtask counts
 80 | 			const subtaskCounts = tasks.reduce(
 81 | 				(acc, task) => {
 82 | 					if (task.subtasks && task.subtasks.length > 0) {
 83 | 						acc.totalSubtasks += task.subtasks.length;
 84 | 						task.subtasks.forEach((subtask) => {
 85 | 							const subStatus = subtask.status || 'pending';
 86 | 							acc.subtasksByStatus[subStatus] =
 87 | 								(acc.subtasksByStatus[subStatus] || 0) + 1;
 88 | 						});
 89 | 					}
 90 | 					return acc;
 91 | 				},
 92 | 				{ totalSubtasks: 0, subtasksByStatus: {} }
 93 | 			);
 94 | 
 95 | 			return {
 96 | 				name: tag.name,
 97 | 				isCurrent: tag.isCurrent,
 98 | 				taskCount: tasks.length,
 99 | 				completedTasks: tag.completedTasks,
100 | 				statusBreakdown,
101 | 				subtaskCounts,
102 | 				created: tag.created,
103 | 				description: tag.description
104 | 			};
105 | 		});
106 | 
107 | 		// Restore normal logging
108 | 		disableSilentMode();
109 | 
110 | 		return {
111 | 			success: true,
112 | 			data: {
113 | 				tags: tagsSummary,
114 | 				currentTag: result.currentTag,
115 | 				totalTags: result.totalTags,
116 | 				message: `Found ${result.totalTags} tag(s)`
117 | 			}
118 | 		};
119 | 	} catch (error) {
120 | 		// Make sure to restore normal logging even if there's an error
121 | 		disableSilentMode();
122 | 
123 | 		log.error(`Error in listTagsDirect: ${error.message}`);
124 | 		return {
125 | 			success: false,
126 | 			error: {
127 | 				code: error.code || 'LIST_TAGS_ERROR',
128 | 				message: error.message
129 | 			}
130 | 		};
131 | 	}
132 | }
133 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/tools/set-task-status.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * tools/setTaskStatus.js
  3 |  * Tool to set the status of a task
  4 |  */
  5 | 
  6 | import { z } from 'zod';
  7 | import {
  8 | 	handleApiResult,
  9 | 	createErrorResponse,
 10 | 	withNormalizedProjectRoot
 11 | } from './utils.js';
 12 | import {
 13 | 	setTaskStatusDirect,
 14 | 	nextTaskDirect
 15 | } from '../core/task-master-core.js';
 16 | import {
 17 | 	findTasksPath,
 18 | 	findComplexityReportPath
 19 | } from '../core/utils/path-utils.js';
 20 | import { TASK_STATUS_OPTIONS } from '../../../src/constants/task-status.js';
 21 | import { resolveTag } from '../../../scripts/modules/utils.js';
 22 | 
 23 | /**
 24 |  * Register the setTaskStatus tool with the MCP server
 25 |  * @param {Object} server - FastMCP server instance
 26 |  */
 27 | export function registerSetTaskStatusTool(server) {
 28 | 	server.addTool({
 29 | 		name: 'set_task_status',
 30 | 		description: 'Set the status of one or more tasks or subtasks.',
 31 | 		parameters: z.object({
 32 | 			id: z
 33 | 				.string()
 34 | 				.describe(
 35 | 					"Task ID or subtask ID (e.g., '15', '15.2'). Can be comma-separated to update multiple tasks/subtasks at once."
 36 | 				),
 37 | 			status: z
 38 | 				.enum(TASK_STATUS_OPTIONS)
 39 | 				.describe(
 40 | 					"New status to set (e.g., 'pending', 'done', 'in-progress', 'review', 'deferred', 'cancelled'."
 41 | 				),
 42 | 			file: z.string().optional().describe('Absolute path to the tasks file'),
 43 | 			complexityReport: z
 44 | 				.string()
 45 | 				.optional()
 46 | 				.describe(
 47 | 					'Path to the complexity report file (relative to project root or absolute)'
 48 | 				),
 49 | 			projectRoot: z
 50 | 				.string()
 51 | 				.describe('The directory of the project. Must be an absolute path.'),
 52 | 			tag: z.string().optional().describe('Optional tag context to operate on')
 53 | 		}),
 54 | 		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
 55 | 			try {
 56 | 				log.info(
 57 | 					`Setting status of task(s) ${args.id} to: ${args.status} ${
 58 | 						args.tag ? `in tag: ${args.tag}` : 'in current tag'
 59 | 					}`
 60 | 				);
 61 | 				const resolvedTag = resolveTag({
 62 | 					projectRoot: args.projectRoot,
 63 | 					tag: args.tag
 64 | 				});
 65 | 				// Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot)
 66 | 				let tasksJsonPath;
 67 | 				try {
 68 | 					tasksJsonPath = findTasksPath(
 69 | 						{ projectRoot: args.projectRoot, file: args.file },
 70 | 						log
 71 | 					);
 72 | 				} catch (error) {
 73 | 					log.error(`Error finding tasks.json: ${error.message}`);
 74 | 					return createErrorResponse(
 75 | 						`Failed to find tasks.json: ${error.message}`
 76 | 					);
 77 | 				}
 78 | 
 79 | 				let complexityReportPath;
 80 | 				try {
 81 | 					complexityReportPath = findComplexityReportPath(
 82 | 						{
 83 | 							projectRoot: args.projectRoot,
 84 | 							complexityReport: args.complexityReport,
 85 | 							tag: resolvedTag
 86 | 						},
 87 | 						log
 88 | 					);
 89 | 				} catch (error) {
 90 | 					log.error(`Error finding complexity report: ${error.message}`);
 91 | 				}
 92 | 
 93 | 				const result = await setTaskStatusDirect(
 94 | 					{
 95 | 						tasksJsonPath: tasksJsonPath,
 96 | 						id: args.id,
 97 | 						status: args.status,
 98 | 						complexityReportPath,
 99 | 						projectRoot: args.projectRoot,
100 | 						tag: resolvedTag
101 | 					},
102 | 					log,
103 | 					{ session }
104 | 				);
105 | 
106 | 				if (result.success) {
107 | 					log.info(
108 | 						`Successfully updated status for task(s) ${args.id} to "${args.status}": ${result.data.message}`
109 | 					);
110 | 				} else {
111 | 					log.error(
112 | 						`Failed to update task status: ${result.error?.message || 'Unknown error'}`
113 | 					);
114 | 				}
115 | 
116 | 				return handleApiResult(
117 | 					result,
118 | 					log,
119 | 					'Error setting task status',
120 | 					undefined,
121 | 					args.projectRoot
122 | 				);
123 | 			} catch (error) {
124 | 				log.error(`Error in setTaskStatus tool: ${error.message}`);
125 | 				return createErrorResponse(
126 | 					`Error setting task status: ${error.message}`
127 | 				);
128 | 			}
129 | 		})
130 | 	});
131 | }
132 | 
```

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