#
tokens: 49708/50000 24/975 files (page 13/50)
lines: off (toggle) GitHub
raw markdown copy
This is page 13 of 50. Use http://codebase.md/eyaltoledano/claude-task-master?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

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

```typescript
/**
 * @fileoverview autopilot-start MCP tool
 * Initialize and start a new TDD workflow for a task
 */

import { z } from 'zod';
import {
	handleApiResult,
	withNormalizedProjectRoot
} from '../../shared/utils.js';
import type { MCPContext } from '../../shared/types.js';
import { createTmCore } from '@tm/core';
import { WorkflowService } from '@tm/core';
import type { FastMCP } from 'fastmcp';

const StartWorkflowSchema = z.object({
	taskId: z
		.string()
		.describe(
			'Main task ID to start workflow for (e.g., "1", "2", "HAM-123"). Subtask IDs (e.g., "2.3", "1.1") are not allowed.'
		),
	projectRoot: z
		.string()
		.describe('Absolute path to the project root directory'),
	maxAttempts: z
		.number()
		.optional()
		.default(3)
		.describe('Maximum attempts per subtask (default: 3)'),
	force: z
		.boolean()
		.optional()
		.default(false)
		.describe('Force start even if workflow state exists')
});

type StartWorkflowArgs = z.infer<typeof StartWorkflowSchema>;

/**
 * Check if a task ID is a main task (not a subtask)
 * Main tasks: "1", "2", "HAM-123", "PROJ-456"
 * Subtasks: "1.1", "2.3", "HAM-123.1"
 */
function isMainTaskId(taskId: string): boolean {
	// A main task has no dots in the ID after the optional prefix
	// Examples: "1" ✓, "HAM-123" ✓, "1.1" ✗, "HAM-123.1" ✗
	const parts = taskId.split('.');
	return parts.length === 1;
}

/**
 * Register the autopilot_start tool with the MCP server
 */
export function registerAutopilotStartTool(server: FastMCP) {
	server.addTool({
		name: 'autopilot_start',
		description:
			'Initialize and start a new TDD workflow for a task. Creates a git branch and sets up the workflow state machine.',
		parameters: StartWorkflowSchema,
		execute: withNormalizedProjectRoot(
			async (args: StartWorkflowArgs, context: MCPContext) => {
				const { taskId, projectRoot, maxAttempts, force } = args;

				try {
					context.log.info(
						`Starting autopilot workflow for task ${taskId} in ${projectRoot}`
					);

					// Validate that taskId is a main task (not a subtask)
					if (!isMainTaskId(taskId)) {
						return handleApiResult({
							result: {
								success: false,
								error: {
									message: `Task ID "${taskId}" is a subtask. Autopilot workflows can only be started for main tasks (e.g., "1", "2", "HAM-123"). Please provide the parent task ID instead.`
								}
							},
							log: context.log,
							projectRoot
						});
					}

					// Load task data and get current tag
					const core = await createTmCore({
						projectPath: projectRoot
					});

					// Get current tag from ConfigManager
					const currentTag = core.config.getActiveTag();

					const taskResult = await core.tasks.get(taskId);

					if (!taskResult || !taskResult.task) {
						return handleApiResult({
							result: {
								success: false,
								error: { message: `Task ${taskId} not found` }
							},
							log: context.log,
							projectRoot
						});
					}

					const task = taskResult.task;

					// Validate task has subtasks
					if (!task.subtasks || task.subtasks.length === 0) {
						return handleApiResult({
							result: {
								success: false,
								error: {
									message: `Task ${taskId} has no subtasks. Please use expand_task (with id="${taskId}") to create subtasks first. For improved results, consider running analyze_complexity before expanding the task.`
								}
							},
							log: context.log,
							projectRoot
						});
					}

					// Initialize workflow service
					const workflowService = new WorkflowService(projectRoot);

					// Check for existing workflow
					const hasWorkflow = await workflowService.hasWorkflow();
					if (hasWorkflow && !force) {
						context.log.warn('Workflow state already exists');
						return handleApiResult({
							result: {
								success: false,
								error: {
									message:
										'Workflow already in progress. Use force=true to override or resume the existing workflow. Suggestion: Use autopilot_resume to continue the existing workflow'
								}
							},
							log: context.log,
							projectRoot
						});
					}

					// Start workflow
					const status = await workflowService.startWorkflow({
						taskId,
						taskTitle: task.title,
						subtasks: task.subtasks.map((st: any) => ({
							id: st.id,
							title: st.title,
							status: st.status,
							maxAttempts
						})),
						maxAttempts,
						force,
						tag: currentTag // Pass current tag for branch naming
					});

					context.log.info(`Workflow started successfully for task ${taskId}`);

					// Get next action with guidance from WorkflowService
					const nextAction = workflowService.getNextAction();

					return handleApiResult({
						result: {
							success: true,
							data: {
								message: `Workflow started for task ${taskId}`,
								taskId,
								branchName: status.branchName,
								phase: status.phase,
								tddPhase: status.tddPhase,
								progress: status.progress,
								currentSubtask: status.currentSubtask,
								nextAction: nextAction.action,
								nextSteps: nextAction.nextSteps
							}
						},
						log: context.log,
						projectRoot
					});
				} catch (error: any) {
					context.log.error(`Error in autopilot-start: ${error.message}`);
					if (error.stack) {
						context.log.debug(error.stack);
					}
					return handleApiResult({
						result: {
							success: false,
							error: { message: `Failed to start workflow: ${error.message}` }
						},
						log: context.log,
						projectRoot
					});
				}
			}
		)
	});
}

```

--------------------------------------------------------------------------------
/apps/cli/src/commands/autopilot/shared.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Shared utilities for autopilot commands
 */

import {
	CommitMessageGenerator,
	GitAdapter,
	WorkflowOrchestrator,
	WorkflowStateManager
} from '@tm/core';
import type { SubtaskInfo, WorkflowContext, WorkflowState } from '@tm/core';
import chalk from 'chalk';

/**
 * Base options interface for all autopilot commands
 */
export interface AutopilotBaseOptions {
	projectRoot?: string;
	json?: boolean;
	verbose?: boolean;
}

/**
 * Load workflow state from disk using WorkflowStateManager
 */
export async function loadWorkflowState(
	projectRoot: string
): Promise<WorkflowState | null> {
	const stateManager = new WorkflowStateManager(projectRoot);

	if (!(await stateManager.exists())) {
		return null;
	}

	try {
		return await stateManager.load();
	} catch (error) {
		throw new Error(
			`Failed to load workflow state: ${(error as Error).message}`
		);
	}
}

/**
 * Save workflow state to disk using WorkflowStateManager
 */
export async function saveWorkflowState(
	projectRoot: string,
	state: WorkflowState
): Promise<void> {
	const stateManager = new WorkflowStateManager(projectRoot);

	try {
		await stateManager.save(state);
	} catch (error) {
		throw new Error(
			`Failed to save workflow state: ${(error as Error).message}`
		);
	}
}

/**
 * Delete workflow state from disk using WorkflowStateManager
 */
export async function deleteWorkflowState(projectRoot: string): Promise<void> {
	const stateManager = new WorkflowStateManager(projectRoot);
	await stateManager.delete();
}

/**
 * Check if workflow state exists using WorkflowStateManager
 */
export async function hasWorkflowState(projectRoot: string): Promise<boolean> {
	const stateManager = new WorkflowStateManager(projectRoot);
	return await stateManager.exists();
}

/**
 * Initialize WorkflowOrchestrator with persistence
 */
export function createOrchestrator(
	context: WorkflowContext,
	projectRoot: string
): WorkflowOrchestrator {
	const orchestrator = new WorkflowOrchestrator(context);
	const stateManager = new WorkflowStateManager(projectRoot);

	// Enable auto-persistence
	orchestrator.enableAutoPersist(async (state: WorkflowState) => {
		await stateManager.save(state);
	});

	return orchestrator;
}

/**
 * Initialize GitAdapter for project
 */
export function createGitAdapter(projectRoot: string): GitAdapter {
	return new GitAdapter(projectRoot);
}

/**
 * Initialize CommitMessageGenerator
 */
export function createCommitMessageGenerator(): CommitMessageGenerator {
	return new CommitMessageGenerator();
}

/**
 * Output formatter for JSON and text modes
 */
export class OutputFormatter {
	constructor(private useJson: boolean) {}

	/**
	 * Output data in appropriate format
	 */
	output(data: Record<string, unknown>): void {
		if (this.useJson) {
			console.log(JSON.stringify(data, null, 2));
		} else {
			this.outputText(data);
		}
	}

	/**
	 * Output data in human-readable text format
	 */
	private outputText(data: Record<string, unknown>): void {
		for (const [key, value] of Object.entries(data)) {
			if (typeof value === 'object' && value !== null) {
				console.log(chalk.cyan(`${key}:`));
				this.outputObject(value as Record<string, unknown>, '  ');
			} else {
				console.log(chalk.white(`${key}: ${value}`));
			}
		}
	}

	/**
	 * Output nested object with indentation
	 */
	private outputObject(obj: Record<string, unknown>, indent: string): void {
		for (const [key, value] of Object.entries(obj)) {
			if (typeof value === 'object' && value !== null) {
				console.log(chalk.cyan(`${indent}${key}:`));
				this.outputObject(value as Record<string, unknown>, indent + '  ');
			} else {
				console.log(chalk.gray(`${indent}${key}: ${value}`));
			}
		}
	}

	/**
	 * Output error message
	 */
	error(message: string, details?: Record<string, unknown>): void {
		if (this.useJson) {
			console.error(
				JSON.stringify(
					{
						error: message,
						...details
					},
					null,
					2
				)
			);
		} else {
			console.error(chalk.red(`Error: ${message}`));
			if (details) {
				for (const [key, value] of Object.entries(details)) {
					console.error(chalk.gray(`  ${key}: ${value}`));
				}
			}
		}
	}

	/**
	 * Output success message
	 */
	success(message: string, data?: Record<string, unknown>): void {
		if (this.useJson) {
			console.log(
				JSON.stringify(
					{
						success: true,
						message,
						...data
					},
					null,
					2
				)
			);
		} else {
			console.log(chalk.green(`✓ ${message}`));
			if (data) {
				this.output(data);
			}
		}
	}

	/**
	 * Output warning message
	 */
	warning(message: string): void {
		if (this.useJson) {
			console.warn(
				JSON.stringify(
					{
						warning: message
					},
					null,
					2
				)
			);
		} else {
			console.warn(chalk.yellow(`⚠️ ${message}`));
		}
	}

	/**
	 * Output info message
	 */
	info(message: string): void {
		if (this.useJson) {
			// Don't output info messages in JSON mode
			return;
		}
		console.log(chalk.blue(`ℹ ${message}`));
	}
}

/**
 * Validate task ID format
 */
export function validateTaskId(taskId: string): boolean {
	// Task ID should be in format: number or number.number (e.g., "1" or "1.2")
	const pattern = /^\d+(\.\d+)*$/;
	return pattern.test(taskId);
}

/**
 * Parse subtasks from task data
 */
export function parseSubtasks(
	task: any,
	maxAttempts: number = 3
): SubtaskInfo[] {
	if (!task.subtasks || !Array.isArray(task.subtasks)) {
		return [];
	}

	return task.subtasks.map((subtask: any) => ({
		id: subtask.id,
		title: subtask.title,
		status: subtask.status === 'done' ? 'completed' : 'pending',
		attempts: 0,
		maxAttempts
	}));
}

```

--------------------------------------------------------------------------------
/src/profiles/roo.js:
--------------------------------------------------------------------------------

```javascript
// Roo Code conversion profile for rule-transformer
import path from 'path';
import fs from 'fs';
import { isSilentMode, log } from '../../scripts/modules/utils.js';
import { createProfile, COMMON_TOOL_MAPPINGS } from './base-profile.js';
import { ROO_MODES } from '../constants/profiles.js';

// Import the shared MCP configuration helper
import { formatJSONWithTabs } from '../utils/create-mcp-config.js';

// Roo-specific MCP configuration enhancements
function enhanceRooMCPConfiguration(mcpPath) {
	if (!fs.existsSync(mcpPath)) {
		log('warn', `[Roo] MCP configuration file not found at ${mcpPath}`);
		return;
	}

	try {
		// Read the existing configuration
		const mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));

		if (mcpConfig.mcpServers && mcpConfig.mcpServers['task-master-ai']) {
			const server = mcpConfig.mcpServers['task-master-ai'];

			// Add Roo-specific timeout enhancement for long-running AI operations
			server.timeout = 300;

			// Write the enhanced configuration back
			fs.writeFileSync(mcpPath, formatJSONWithTabs(mcpConfig) + '\n');
			log(
				'debug',
				`[Roo] Enhanced MCP configuration with timeout at ${mcpPath}`
			);
		} else {
			log('warn', `[Roo] task-master-ai server not found in MCP configuration`);
		}
	} catch (error) {
		log('error', `[Roo] Failed to enhance MCP configuration: ${error.message}`);
	}
}

// Lifecycle functions for Roo profile
function onAddRulesProfile(targetDir, assetsDir) {
	// Use the provided assets directory to find the roocode directory
	const sourceDir = path.join(assetsDir, 'roocode');

	if (!fs.existsSync(sourceDir)) {
		log('error', `[Roo] Source directory does not exist: ${sourceDir}`);
		return;
	}

	copyRecursiveSync(sourceDir, targetDir);
	log('debug', `[Roo] Copied roocode directory to ${targetDir}`);

	const rooModesDir = path.join(sourceDir, '.roo');

	// Copy .roomodes to project root
	const roomodesSrc = path.join(sourceDir, '.roomodes');
	const roomodesDest = path.join(targetDir, '.roomodes');
	if (fs.existsSync(roomodesSrc)) {
		try {
			fs.copyFileSync(roomodesSrc, roomodesDest);
			log('debug', `[Roo] Copied .roomodes to ${roomodesDest}`);
		} catch (err) {
			log('error', `[Roo] Failed to copy .roomodes: ${err.message}`);
		}
	}

	// Note: MCP configuration is now handled by the base profile system
	// The base profile will call setupMCPConfiguration, and we enhance it in onPostConvert

	for (const mode of ROO_MODES) {
		const src = path.join(rooModesDir, `rules-${mode}`, `${mode}-rules`);
		const dest = path.join(targetDir, '.roo', `rules-${mode}`, `${mode}-rules`);
		if (fs.existsSync(src)) {
			try {
				const destDir = path.dirname(dest);
				if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
				fs.copyFileSync(src, dest);
				log('debug', `[Roo] Copied ${mode}-rules to ${dest}`);
			} catch (err) {
				log('error', `[Roo] Failed to copy ${src} to ${dest}: ${err.message}`);
			}
		}
	}
}

function copyRecursiveSync(src, dest) {
	const exists = fs.existsSync(src);
	const stats = exists && fs.statSync(src);
	const isDirectory = exists && stats.isDirectory();
	if (isDirectory) {
		if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
		fs.readdirSync(src).forEach((childItemName) => {
			copyRecursiveSync(
				path.join(src, childItemName),
				path.join(dest, childItemName)
			);
		});
	} else {
		fs.copyFileSync(src, dest);
	}
}

function onRemoveRulesProfile(targetDir) {
	const roomodesPath = path.join(targetDir, '.roomodes');
	if (fs.existsSync(roomodesPath)) {
		try {
			fs.rmSync(roomodesPath, { force: true });
			log('debug', `[Roo] Removed .roomodes from ${roomodesPath}`);
		} catch (err) {
			log('error', `[Roo] Failed to remove .roomodes: ${err.message}`);
		}
	}

	const rooDir = path.join(targetDir, '.roo');
	if (fs.existsSync(rooDir)) {
		// Remove MCP configuration
		const mcpPath = path.join(rooDir, 'mcp.json');
		try {
			fs.rmSync(mcpPath, { force: true });
			log('debug', `[Roo] Removed MCP configuration from ${mcpPath}`);
		} catch (err) {
			log('error', `[Roo] Failed to remove MCP configuration: ${err.message}`);
		}

		fs.readdirSync(rooDir).forEach((entry) => {
			if (entry.startsWith('rules-')) {
				const modeDir = path.join(rooDir, entry);
				try {
					fs.rmSync(modeDir, { recursive: true, force: true });
					log('debug', `[Roo] Removed ${entry} directory from ${modeDir}`);
				} catch (err) {
					log('error', `[Roo] Failed to remove ${modeDir}: ${err.message}`);
				}
			}
		});
		if (fs.readdirSync(rooDir).length === 0) {
			try {
				fs.rmSync(rooDir, { recursive: true, force: true });
				log('debug', `[Roo] Removed empty .roo directory from ${rooDir}`);
			} catch (err) {
				log('error', `[Roo] Failed to remove .roo directory: ${err.message}`);
			}
		}
	}
}

function onPostConvertRulesProfile(targetDir, assetsDir) {
	// Enhance the MCP configuration with Roo-specific features after base setup
	const mcpPath = path.join(targetDir, '.roo', 'mcp.json');
	try {
		enhanceRooMCPConfiguration(mcpPath);
	} catch (err) {
		log('error', `[Roo] Failed to enhance MCP configuration: ${err.message}`);
	}
}

// Create and export roo profile using the base factory
export const rooProfile = createProfile({
	name: 'roo',
	displayName: 'Roo Code',
	url: 'roocode.com',
	docsUrl: 'docs.roocode.com',
	toolMappings: COMMON_TOOL_MAPPINGS.ROO_STYLE,
	mcpConfig: true, // Enable MCP config - we enhance it with Roo-specific features
	onAdd: onAddRulesProfile,
	onRemove: onRemoveRulesProfile,
	onPostConvert: onPostConvertRulesProfile
});

// Export lifecycle functions separately to avoid naming conflicts
export { onAddRulesProfile, onRemoveRulesProfile, onPostConvertRulesProfile };

```

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

```typescript
/**
 * @fileoverview Auth Domain Facade
 * Public API for authentication and authorization
 */

import path from 'node:path';
import type { StorageType } from '../../common/types/index.js';
import type { Brief } from '../briefs/types.js';
import { AuthManager } from './managers/auth-manager.js';
import type {
	Organization,
	RemoteTask
} from './services/organization.service.js';
import type {
	AuthCredentials,
	OAuthFlowOptions,
	UserContext
} from './types.js';

/**
 * Display information for storage context
 */
export interface StorageDisplayInfo {
	storageType: Exclude<StorageType, 'auto'>;
	briefInfo?: {
		briefId: string;
		briefName: string;
		orgSlug?: string;
		webAppUrl?: string;
	};
	filePath?: string;
}

/**
 * Auth Domain - Unified API for authentication operations
 */
export class AuthDomain {
	private authManager: AuthManager;

	constructor() {
		this.authManager = AuthManager.getInstance();
	}

	// ========== Authentication ==========

	/**
	 * Check if valid Supabase session exists
	 */
	async hasValidSession(): Promise<boolean> {
		return this.authManager.hasValidSession();
	}

	/**
	 * Get the current Supabase session with full details
	 */
	async getSession() {
		return this.authManager.getSession();
	}

	/**
	 * Get stored user context (userId, email)
	 */
	getStoredContext() {
		return this.authManager.getStoredContext();
	}

	/**
	 * Get stored credentials
	 */
	async getCredentials(): Promise<AuthCredentials | null> {
		return this.authManager.getAuthCredentials();
	}

	/**
	 * Get access token from current session
	 */
	async getAccessToken(): Promise<string | null> {
		return this.authManager.getAccessToken();
	}

	/**
	 * Authenticate with OAuth flow
	 */
	async authenticateWithOAuth(
		options?: OAuthFlowOptions
	): Promise<AuthCredentials> {
		return this.authManager.authenticateWithOAuth(options);
	}

	/**
	 * Authenticate using a one-time token
	 * Useful for CLI authentication in SSH/remote environments
	 */
	async authenticateWithCode(token: string): Promise<AuthCredentials> {
		return this.authManager.authenticateWithCode(token);
	}

	/**
	 * Get OAuth authorization URL
	 */
	getAuthorizationUrl(): string | null {
		return this.authManager.getAuthorizationUrl();
	}

	/**
	 * Refresh authentication token
	 */
	async refreshToken(): Promise<AuthCredentials> {
		return this.authManager.refreshToken();
	}

	/**
	 * Logout current user
	 */
	async logout(): Promise<void> {
		return this.authManager.logout();
	}

	// ========== User Context Management ==========

	/**
	 * Get current user context (org/brief selection)
	 */
	getContext(): UserContext | null {
		return this.authManager.getContext();
	}

	/**
	 * Update user context
	 */
	async updateContext(context: Partial<UserContext>): Promise<void> {
		return this.authManager.updateContext(context);
	}

	/**
	 * Clear user context
	 */
	async clearContext(): Promise<void> {
		return this.authManager.clearContext();
	}

	// ========== Organization Management ==========

	/**
	 * Get all organizations for the authenticated user
	 */
	async getOrganizations(): Promise<Organization[]> {
		return this.authManager.getOrganizations();
	}

	/**
	 * Get a specific organization by ID
	 */
	async getOrganization(orgId: string): Promise<Organization | null> {
		return this.authManager.getOrganization(orgId);
	}

	/**
	 * Get all briefs for a specific organization
	 */
	async getBriefs(orgId: string): Promise<Brief[]> {
		return this.authManager.getBriefs(orgId);
	}

	/**
	 * Get a specific brief by ID
	 */
	async getBrief(briefId: string): Promise<Brief | null> {
		return this.authManager.getBrief(briefId);
	}

	/**
	 * Get all tasks for a specific brief
	 */
	async getTasks(briefId: string): Promise<RemoteTask[]> {
		return this.authManager.getTasks(briefId);
	}

	// ========== Display Information ==========

	/**
	 * Get storage display information for UI presentation
	 * Includes brief info for API storage, file path for file storage
	 *
	 * @param resolvedStorageType - The actual storage type being used at runtime.
	 *                              Get this from tmCore.tasks.getStorageType()
	 */
	getStorageDisplayInfo(
		resolvedStorageType: 'file' | 'api'
	): StorageDisplayInfo {
		if (resolvedStorageType === 'api') {
			const context = this.getContext();
			if (context?.briefId && context?.briefName) {
				return {
					storageType: 'api',
					briefInfo: {
						briefId: context.briefId,
						briefName: context.briefName,
						orgSlug: context.orgSlug,
						webAppUrl: this.getWebAppUrl()
					}
				};
			}
		}

		// Default to file storage display
		return {
			storageType: 'file',
			filePath: path.join('.taskmaster', 'tasks', 'tasks.json')
		};
	}

	/**
	 * Get the URL for creating a new brief in the web UI
	 * Returns null if not using API storage or if org slug is not available
	 */
	getBriefCreationUrl(): string | null {
		const context = this.getContext();
		const baseUrl = this.getWebAppUrl();

		if (!baseUrl || !context?.orgSlug) {
			return null;
		}

		return `${baseUrl}/home/${context.orgSlug}/briefs/create`;
	}

	/**
	 * Get web app base URL from environment configuration
	 * @private
	 */
	private getWebAppUrl(): string | undefined {
		const baseDomain =
			process.env.TM_BASE_DOMAIN || process.env.TM_PUBLIC_BASE_DOMAIN;

		if (!baseDomain) {
			return undefined;
		}

		// If it already includes protocol, use as-is
		if (baseDomain.startsWith('http://') || baseDomain.startsWith('https://')) {
			return baseDomain;
		}

		// Otherwise, add protocol based on domain
		if (baseDomain.includes('localhost') || baseDomain.includes('127.0.0.1')) {
			return `http://${baseDomain}`;
		}

		return `https://${baseDomain}`;
	}
}

```

--------------------------------------------------------------------------------
/apps/docs/best-practices/advanced-tasks.mdx:
--------------------------------------------------------------------------------

```markdown
---
title: Advanced Tasks
sidebarTitle: "Advanced Tasks"
---

## AI-Driven Development Workflow

The Cursor agent is pre-configured (via the rules file) to follow this workflow:

### 1. Task Discovery and Selection

Ask the agent to list available tasks:

```
What tasks are available to work on next?
```

```
Can you show me tasks 1, 3, and 5 to understand their current status?
```

The agent will:

- Run `task-master list` to see all tasks
- Run `task-master next` to determine the next task to work on
- Run `task-master show 1,3,5` to display multiple tasks with interactive options
- Analyze dependencies to determine which tasks are ready to be worked on
- Prioritize tasks based on priority level and ID order
- Suggest the next task(s) to implement

### 2. Task Implementation

When implementing a task, the agent will:

- Reference the task's details section for implementation specifics
- Consider dependencies on previous tasks
- Follow the project's coding standards
- Create appropriate tests based on the task's testStrategy

You can ask:

```
Let's implement task 3. What does it involve?
```

### 2.1. Viewing Multiple Tasks

For efficient context gathering and batch operations:

```
Show me tasks 5, 7, and 9 so I can plan my implementation approach.
```

The agent will:

- Run `task-master show 5,7,9` to display a compact summary table
- Show task status, priority, and progress indicators
- Provide an interactive action menu with batch operations
- Allow you to perform group actions like marking multiple tasks as in-progress

### 3. Task Verification

Before marking a task as complete, verify it according to:

- The task's specified testStrategy
- Any automated tests in the codebase
- Manual verification if required

### 4. Task Completion

When a task is completed, tell the agent:

```
Task 3 is now complete. Please update its status.
```

The agent will execute:

```bash
task-master set-status --id=3 --status=done
```

### 5. Handling Implementation Drift

If during implementation, you discover that:

- The current approach differs significantly from what was planned
- Future tasks need to be modified due to current implementation choices
- New dependencies or requirements have emerged

Tell the agent:

```
We've decided to use MongoDB instead of PostgreSQL. Can you update all future tasks (from ID 4) to reflect this change?
```

The agent will execute:

```bash
task-master update --from=4 --prompt="Now we are using MongoDB instead of PostgreSQL."

# OR, if research is needed to find best practices for MongoDB:
task-master update --from=4 --prompt="Update to use MongoDB, researching best practices" --research
```

This will rewrite or re-scope subsequent tasks in tasks.json while preserving completed work.

### 6. Reorganizing Tasks

If you need to reorganize your task structure:

```
I think subtask 5.2 would fit better as part of task 7 instead. Can you move it there?
```

The agent will execute:

```bash
task-master move --from=5.2 --to=7.3
```

You can reorganize tasks in various ways:

- Moving a standalone task to become a subtask: `--from=5 --to=7`
- Moving a subtask to become a standalone task: `--from=5.2 --to=7`
- Moving a subtask to a different parent: `--from=5.2 --to=7.3`
- Reordering subtasks within the same parent: `--from=5.2 --to=5.4`
- Moving a task to a new ID position: `--from=5 --to=25` (even if task 25 doesn't exist yet)
- Moving multiple tasks at once: `--from=10,11,12 --to=16,17,18` (must have same number of IDs, Taskmaster will look through each position)

When moving tasks to new IDs:

- The system automatically creates placeholder tasks for non-existent destination IDs
- This prevents accidental data loss during reorganization
- Any tasks that depend on moved tasks will have their dependencies updated
- When moving a parent task, all its subtasks are automatically moved with it and renumbered

This is particularly useful as your project understanding evolves and you need to refine your task structure.

### 7. Resolving Merge Conflicts with Tasks

When working with a team, you might encounter merge conflicts in your tasks.json file if multiple team members create tasks on different branches. The move command makes resolving these conflicts straightforward:

```
I just merged the main branch and there's a conflict with tasks.json. My teammates created tasks 10-15 while I created tasks 10-12 on my branch. Can you help me resolve this?
```

The agent will help you:

1. Keep your teammates' tasks (10-15)
2. Move your tasks to new positions to avoid conflicts:

```bash
# Move your tasks to new positions (e.g., 16-18)
task-master move --from=10 --to=16
task-master move --from=11 --to=17
task-master move --from=12 --to=18
```

This approach preserves everyone's work while maintaining a clean task structure, making it much easier to handle task conflicts than trying to manually merge JSON files.

### 8. Breaking Down Complex Tasks

For complex tasks that need more granularity:

```
Task 5 seems complex. Can you break it down into subtasks?
```

The agent will execute:

```bash
task-master expand --id=5 --num=3
```

You can provide additional context:

```
Please break down task 5 with a focus on security considerations.
```

The agent will execute:

```bash
task-master expand --id=5 --prompt="Focus on security aspects"
```

You can also expand all pending tasks:

```
Please break down all pending tasks into subtasks.
```

The agent will execute:

```bash
task-master expand --all
```

For research-backed subtask generation using the configured research model:

```
Please break down task 5 using research-backed generation.
```

The agent will execute:

```bash
task-master expand --id=5 --research
```
```

--------------------------------------------------------------------------------
/packages/tm-core/src/modules/config/services/config-merger.service.spec.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Unit tests for ConfigMerger service
 */

import { beforeEach, describe, expect, it } from 'vitest';
import { CONFIG_PRECEDENCE, ConfigMerger } from './config-merger.service.js';

describe('ConfigMerger', () => {
	let merger: ConfigMerger;

	beforeEach(() => {
		merger = new ConfigMerger();
	});

	describe('addSource', () => {
		it('should add configuration source', () => {
			const source = {
				name: 'test',
				config: { test: true },
				precedence: 1
			};

			merger.addSource(source);
			const sources = merger.getSources();

			expect(sources).toHaveLength(1);
			expect(sources[0]).toEqual(source);
		});

		it('should add multiple sources', () => {
			merger.addSource({ name: 'source1', config: {}, precedence: 1 });
			merger.addSource({ name: 'source2', config: {}, precedence: 2 });

			expect(merger.getSources()).toHaveLength(2);
		});
	});

	describe('clearSources', () => {
		it('should remove all configuration sources', () => {
			merger.addSource({ name: 'test', config: {}, precedence: 1 });
			merger.clearSources();

			expect(merger.getSources()).toHaveLength(0);
		});
	});

	describe('merge', () => {
		it('should merge configurations based on precedence', () => {
			merger.addSource({
				name: 'low',
				config: { a: 1, b: 2 },
				precedence: 1
			});

			merger.addSource({
				name: 'high',
				config: { a: 3, c: 4 },
				precedence: 2
			});

			const result = merger.merge();

			expect(result).toEqual({
				a: 3, // High precedence wins
				b: 2, // Only in low
				c: 4 // Only in high
			});
		});

		it('should deep merge nested objects', () => {
			merger.addSource({
				name: 'base',
				config: {
					models: { main: 'model1', fallback: 'model2' },
					storage: { type: 'file' as const }
				},
				precedence: 1
			});

			merger.addSource({
				name: 'override',
				config: {
					models: { main: 'model3' },
					storage: { encoding: 'utf8' as const }
				},
				precedence: 2
			});

			const result = merger.merge();

			expect(result).toEqual({
				models: {
					main: 'model3', // Overridden
					fallback: 'model2' // Preserved
				},
				storage: {
					type: 'file', // Preserved
					encoding: 'utf8' // Added
				}
			});
		});

		it('should handle arrays by replacement', () => {
			merger.addSource({
				name: 'base',
				config: { items: [1, 2, 3] },
				precedence: 1
			});

			merger.addSource({
				name: 'override',
				config: { items: [4, 5] },
				precedence: 2
			});

			const result = merger.merge();

			expect(result.items).toEqual([4, 5]); // Arrays are replaced, not merged
		});

		it('should ignore null and undefined values', () => {
			merger.addSource({
				name: 'base',
				config: { a: 1, b: 2 },
				precedence: 1
			});

			merger.addSource({
				name: 'override',
				config: { a: null, b: undefined, c: 3 } as any,
				precedence: 2
			});

			const result = merger.merge();

			expect(result).toEqual({
				a: 1, // null ignored
				b: 2, // undefined ignored
				c: 3 // new value added
			});
		});

		it('should return empty object when no sources', () => {
			const result = merger.merge();
			expect(result).toEqual({});
		});

		it('should use CONFIG_PRECEDENCE constants correctly', () => {
			merger.addSource({
				name: 'defaults',
				config: { level: 'default' },
				precedence: CONFIG_PRECEDENCE.DEFAULTS
			});

			merger.addSource({
				name: 'local',
				config: { level: 'local' },
				precedence: CONFIG_PRECEDENCE.LOCAL
			});

			merger.addSource({
				name: 'environment',
				config: { level: 'env' },
				precedence: CONFIG_PRECEDENCE.ENVIRONMENT
			});

			const result = merger.merge();

			expect(result.level).toBe('env'); // Highest precedence wins
		});
	});

	describe('getSources', () => {
		it('should return sources sorted by precedence (highest first)', () => {
			merger.addSource({ name: 'low', config: {}, precedence: 1 });
			merger.addSource({ name: 'high', config: {}, precedence: 3 });
			merger.addSource({ name: 'medium', config: {}, precedence: 2 });

			const sources = merger.getSources();

			expect(sources[0].name).toBe('high');
			expect(sources[1].name).toBe('medium');
			expect(sources[2].name).toBe('low');
		});

		it('should return a copy of sources array', () => {
			merger.addSource({ name: 'test', config: {}, precedence: 1 });

			const sources1 = merger.getSources();
			const sources2 = merger.getSources();

			expect(sources1).not.toBe(sources2); // Different array instances
			expect(sources1).toEqual(sources2); // Same content
		});
	});

	describe('hasSource', () => {
		it('should return true when source exists', () => {
			merger.addSource({ name: 'test', config: {}, precedence: 1 });

			expect(merger.hasSource('test')).toBe(true);
		});

		it('should return false when source does not exist', () => {
			expect(merger.hasSource('nonexistent')).toBe(false);
		});
	});

	describe('removeSource', () => {
		it('should remove source by name and return true', () => {
			merger.addSource({ name: 'test', config: {}, precedence: 1 });
			merger.addSource({ name: 'keep', config: {}, precedence: 2 });

			const removed = merger.removeSource('test');

			expect(removed).toBe(true);
			expect(merger.hasSource('test')).toBe(false);
			expect(merger.hasSource('keep')).toBe(true);
		});

		it('should return false when source does not exist', () => {
			const removed = merger.removeSource('nonexistent');

			expect(removed).toBe(false);
		});

		it('should handle removing all sources', () => {
			merger.addSource({ name: 'test1', config: {}, precedence: 1 });
			merger.addSource({ name: 'test2', config: {}, precedence: 2 });

			merger.removeSource('test1');
			merger.removeSource('test2');

			expect(merger.getSources()).toHaveLength(0);
		});
	});
});

```

--------------------------------------------------------------------------------
/packages/tm-core/src/modules/storage/adapters/file-storage/format-handler.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Format handler for task storage files
 */

import type { Task, TaskMetadata } from '../../../../common/types/index.js';

export interface FileStorageData {
	tasks: Task[];
	metadata: TaskMetadata;
}

export type FileFormat = 'legacy' | 'standard';

/**
 * Handles format detection and conversion between legacy and standard task file formats
 */
export class FormatHandler {
	/**
	 * Detect the format of the raw data
	 */
	detectFormat(data: any): FileFormat {
		if (!data || typeof data !== 'object') {
			return 'standard';
		}

		const keys = Object.keys(data);

		// Check if this uses the legacy format with tag keys
		// Legacy format has keys that are not 'tasks' or 'metadata'
		const hasLegacyFormat = keys.some(
			(key) => key !== 'tasks' && key !== 'metadata'
		);

		return hasLegacyFormat ? 'legacy' : 'standard';
	}

	/**
	 * Extract tasks from data for a specific tag
	 */
	extractTasks(data: any, tag: string): Task[] {
		if (!data) {
			return [];
		}

		const format = this.detectFormat(data);

		if (format === 'legacy') {
			return this.extractTasksFromLegacy(data, tag);
		}

		return this.extractTasksFromStandard(data);
	}

	/**
	 * Extract tasks from legacy format
	 */
	private extractTasksFromLegacy(data: any, tag: string): Task[] {
		// First check if the requested tag exists
		if (tag in data) {
			const tagData = data[tag];
			return tagData?.tasks || [];
		}

		// If we're looking for 'master' tag but it doesn't exist, try the first available tag
		const availableKeys = Object.keys(data).filter(
			(key) => key !== 'tasks' && key !== 'metadata'
		);
		if (tag === 'master' && availableKeys.length > 0) {
			const firstTag = availableKeys[0];
			const tagData = data[firstTag];
			return tagData?.tasks || [];
		}

		return [];
	}

	/**
	 * Extract tasks from standard format
	 */
	private extractTasksFromStandard(data: any): Task[] {
		return data?.tasks || [];
	}

	/**
	 * Extract metadata from data for a specific tag
	 */
	extractMetadata(data: any, tag: string): TaskMetadata | null {
		if (!data) {
			return null;
		}

		const format = this.detectFormat(data);

		if (format === 'legacy') {
			return this.extractMetadataFromLegacy(data, tag);
		}

		return this.extractMetadataFromStandard(data);
	}

	/**
	 * Extract metadata from legacy format
	 */
	private extractMetadataFromLegacy(
		data: any,
		tag: string
	): TaskMetadata | null {
		if (tag in data) {
			const tagData = data[tag];
			// Generate metadata if not present in legacy format
			if (!tagData?.metadata && tagData?.tasks) {
				return this.generateMetadataFromTasks(tagData.tasks, tag);
			}
			return tagData?.metadata || null;
		}

		// If we're looking for 'master' tag but it doesn't exist, try the first available tag
		const availableKeys = Object.keys(data).filter(
			(key) => key !== 'tasks' && key !== 'metadata'
		);
		if (tag === 'master' && availableKeys.length > 0) {
			const firstTag = availableKeys[0];
			const tagData = data[firstTag];
			if (!tagData?.metadata && tagData?.tasks) {
				return this.generateMetadataFromTasks(tagData.tasks, firstTag);
			}
			return tagData?.metadata || null;
		}

		return null;
	}

	/**
	 * Extract metadata from standard format
	 */
	private extractMetadataFromStandard(data: any): TaskMetadata | null {
		return data?.metadata || null;
	}

	/**
	 * Extract all available tags from the single tasks.json file
	 */
	extractTags(data: any): string[] {
		if (!data) {
			return [];
		}

		const format = this.detectFormat(data);

		if (format === 'legacy') {
			// Return all tag keys from legacy format
			const keys = Object.keys(data);
			return keys.filter((key) => key !== 'tasks' && key !== 'metadata');
		}

		// Standard format - just has 'master' tag
		return ['master'];
	}

	/**
	 * Convert tasks and metadata to the appropriate format for saving
	 */
	convertToSaveFormat(
		tasks: Task[],
		metadata: TaskMetadata,
		existingData: any,
		tag: string
	): any {
		const resolvedTag = tag || 'master';

		// Normalize task IDs to strings
		const normalizedTasks = this.normalizeTasks(tasks);

		// Check if existing file uses legacy format
		if (existingData && this.detectFormat(existingData) === 'legacy') {
			return this.convertToLegacyFormat(normalizedTasks, metadata, resolvedTag);
		}

		// Use standard format for new files
		return this.convertToStandardFormat(normalizedTasks, metadata, tag);
	}

	/**
	 * Convert to legacy format
	 */
	private convertToLegacyFormat(
		tasks: Task[],
		metadata: TaskMetadata,
		tag: string
	): any {
		return {
			[tag]: {
				tasks,
				metadata: {
					...metadata,
					tags: [tag]
				}
			}
		};
	}

	/**
	 * Convert to standard format
	 */
	private convertToStandardFormat(
		tasks: Task[],
		metadata: TaskMetadata,
		tag?: string
	): FileStorageData {
		return {
			tasks,
			metadata: {
				...metadata,
				tags: tag ? [tag] : []
			}
		};
	}

	/**
	 * Normalize task IDs - keep Task IDs as strings, Subtask IDs as numbers
	 */
	private normalizeTasks(tasks: Task[]): Task[] {
		return tasks.map((task) => ({
			...task,
			id: String(task.id), // Task IDs are strings
			dependencies: task.dependencies?.map((dep) => String(dep)) || [],
			subtasks:
				task.subtasks?.map((subtask) => ({
					...subtask,
					id: Number(subtask.id), // Subtask IDs are numbers
					parentId: String(subtask.parentId) // Parent ID is string (Task ID)
				})) || []
		}));
	}

	/**
	 * Generate metadata from tasks when not present
	 */
	private generateMetadataFromTasks(tasks: Task[], tag: string): TaskMetadata {
		return {
			version: '1.0.0',
			lastModified: new Date().toISOString(),
			taskCount: tasks.length,
			completedCount: tasks.filter((t: any) => t.status === 'done').length,
			tags: [tag]
		};
	}
}

```

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

```javascript
/**
 * add-task.js
 * Direct function implementation for adding a new task
 */

import { addTask } from '../../../../scripts/modules/task-manager.js';
import {
	enableSilentMode,
	disableSilentMode
} from '../../../../scripts/modules/utils.js';
import { createLogWrapper } from '../../tools/utils.js';

/**
 * Direct function wrapper for adding a new task with error handling.
 *
 * @param {Object} args - Command arguments
 * @param {string} [args.prompt] - Description of the task to add (required if not using manual fields)
 * @param {string} [args.title] - Task title (for manual task creation)
 * @param {string} [args.description] - Task description (for manual task creation)
 * @param {string} [args.details] - Implementation details (for manual task creation)
 * @param {string} [args.testStrategy] - Test strategy (for manual task creation)
 * @param {string} [args.dependencies] - Comma-separated list of task IDs this task depends on
 * @param {string} [args.priority='medium'] - Task priority (high, medium, low)
 * @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
 * @param {boolean} [args.research=false] - Whether to use research capabilities for task creation
 * @param {string} [args.projectRoot] - Project root path
 * @param {string} [args.tag] - Tag for the task (optional)
 * @param {Object} log - Logger object
 * @param {Object} context - Additional context (session)
 * @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
 */
export async function addTaskDirect(args, log, context = {}) {
	// Destructure expected args (including research and projectRoot)
	const {
		tasksJsonPath,
		prompt,
		dependencies,
		priority,
		research,
		projectRoot,
		tag
	} = args;
	const { session } = context; // Destructure session from context

	// Enable silent mode to prevent console logs from interfering with JSON response
	enableSilentMode();

	// Create logger wrapper using the utility
	const mcpLog = createLogWrapper(log);

	try {
		// Check if tasksJsonPath was provided
		if (!tasksJsonPath) {
			log.error('addTaskDirect called without tasksJsonPath');
			disableSilentMode(); // Disable before returning
			return {
				success: false,
				error: {
					code: 'MISSING_ARGUMENT',
					message: 'tasksJsonPath is required'
				}
			};
		}

		// Use provided path
		const tasksPath = tasksJsonPath;

		// Check if this is manual task creation or AI-driven task creation
		const isManualCreation = args.title && args.description;

		// Check required parameters
		if (!args.prompt && !isManualCreation) {
			log.error(
				'Missing required parameters: either prompt or title+description must be provided'
			);
			disableSilentMode();
			return {
				success: false,
				error: {
					code: 'MISSING_PARAMETER',
					message:
						'Either the prompt parameter or both title and description parameters are required for adding a task'
				}
			};
		}

		// Extract and prepare parameters
		const taskDependencies = Array.isArray(dependencies)
			? dependencies // Already an array if passed directly
			: dependencies // Check if dependencies exist and are a string
				? String(dependencies)
						.split(',')
						.map((id) => parseInt(id.trim(), 10)) // Split, trim, and parse
				: []; // Default to empty array if null/undefined
		const taskPriority = priority || 'medium'; // Default priority

		let manualTaskData = null;
		let newTaskId;
		let telemetryData;
		let tagInfo;

		if (isManualCreation) {
			// Create manual task data object
			manualTaskData = {
				title: args.title,
				description: args.description,
				details: args.details || '',
				testStrategy: args.testStrategy || ''
			};

			log.info(
				`Adding new task manually with title: "${args.title}", dependencies: [${taskDependencies.join(', ')}], priority: ${priority}`
			);

			// Call the addTask function with manual task data
			const result = await addTask(
				tasksPath,
				null, // prompt is null for manual creation
				taskDependencies,
				taskPriority,
				{
					session,
					mcpLog,
					projectRoot,
					commandName: 'add-task',
					outputType: 'mcp',
					tag
				},
				'json', // outputFormat
				manualTaskData, // Pass the manual task data
				false // research flag is false for manual creation
			);
			newTaskId = result.newTaskId;
			telemetryData = result.telemetryData;
			tagInfo = result.tagInfo;
		} else {
			// AI-driven task creation
			log.info(
				`Adding new task with prompt: "${prompt}", dependencies: [${taskDependencies.join(', ')}], priority: ${taskPriority}, research: ${research}`
			);

			// Call the addTask function, passing the research flag
			const result = await addTask(
				tasksPath,
				prompt, // Use the prompt for AI creation
				taskDependencies,
				taskPriority,
				{
					session,
					mcpLog,
					projectRoot,
					commandName: 'add-task',
					outputType: 'mcp',
					tag
				},
				'json', // outputFormat
				null, // manualTaskData is null for AI creation
				research // Pass the research flag
			);
			newTaskId = result.newTaskId;
			telemetryData = result.telemetryData;
			tagInfo = result.tagInfo;
		}

		// Restore normal logging
		disableSilentMode();

		return {
			success: true,
			data: {
				taskId: newTaskId,
				message: `Successfully added new task #${newTaskId}`,
				telemetryData: telemetryData,
				tagInfo: tagInfo
			}
		};
	} catch (error) {
		// Make sure to restore normal logging even if there's an error
		disableSilentMode();

		log.error(`Error in addTaskDirect: ${error.message}`);
		// Add specific error code checks if needed
		return {
			success: false,
			error: {
				code: error.code || 'ADD_TASK_ERROR', // Use error code if available
				message: error.message
			}
		};
	}
}

```

--------------------------------------------------------------------------------
/scripts/modules/sync-readme.js:
--------------------------------------------------------------------------------

```javascript
import fs from 'fs';
import path from 'path';
import chalk from 'chalk';
import { log, findProjectRoot } from './utils.js';
import { getProjectName } from './config-manager.js';
import listTasks from './task-manager/list-tasks.js';

/**
 * Creates a basic README structure if one doesn't exist
 * @param {string} projectName - Name of the project
 * @returns {string} - Basic README content
 */
function createBasicReadme(projectName) {
	return `# ${projectName}

This project is managed using Task Master.

`;
}

/**
 * Create UTM tracking URL for task-master.dev
 * @param {string} projectRoot - The project root path
 * @returns {string} - UTM tracked URL
 */
function createTaskMasterUrl(projectRoot) {
	// Get the actual folder name from the project root path
	const folderName = path.basename(projectRoot);

	// Clean folder name for UTM (replace spaces/special chars with hyphens)
	const cleanFolderName = folderName
		.toLowerCase()
		.replace(/[^a-z0-9]/g, '-')
		.replace(/-+/g, '-')
		.replace(/^-|-$/g, '');

	const utmParams = new URLSearchParams({
		utm_source: 'github-readme',
		utm_medium: 'readme-export',
		utm_campaign: cleanFolderName || 'task-sync',
		utm_content: 'task-export-link'
	});

	return `https://task-master.dev?${utmParams.toString()}`;
}

/**
 * Create the start marker with metadata
 * @param {Object} options - Export options
 * @returns {string} - Formatted start marker
 */
function createStartMarker(options) {
	const { timestamp, withSubtasks, status, projectRoot } = options;

	// Format status filter text
	const statusText = status
		? `Status filter: ${status}`
		: 'Status filter: none';
	const subtasksText = withSubtasks ? 'with subtasks' : 'without subtasks';

	// Create the export info content
	const exportInfo =
		`🎯 **Taskmaster Export** - ${timestamp}\n` +
		`📋 Export: ${subtasksText} • ${statusText}\n` +
		`🔗 Powered by [Task Master](${createTaskMasterUrl(projectRoot)})`;

	// Create a markdown box using code blocks and emojis to mimic our UI style
	const boxContent =
		`<!-- TASKMASTER_EXPORT_START -->\n` +
		`> ${exportInfo.split('\n').join('\n> ')}\n\n`;

	return boxContent;
}

/**
 * Create the end marker
 * @returns {string} - Formatted end marker
 */
function createEndMarker() {
	return (
		`\n> 📋 **End of Taskmaster Export** - Tasks are synced from your project using the \`sync-readme\` command.\n` +
		`<!-- TASKMASTER_EXPORT_END -->\n`
	);
}

/**
 * Syncs the current task list to README.md at the project root
 * @param {string} projectRoot - Path to the project root directory
 * @param {Object} options - Options for syncing
 * @param {boolean} options.withSubtasks - Include subtasks in the output (default: false)
 * @param {string} options.status - Filter by status (e.g., 'pending', 'done')
 * @param {string} options.tasksPath - Custom path to tasks.json
 * @returns {boolean} - True if sync was successful, false otherwise
 * TODO: Add tag support - this is not currently supported how we want to handle this  - Parthy
 */
export async function syncTasksToReadme(projectRoot = null, options = {}) {
	try {
		const actualProjectRoot = projectRoot || findProjectRoot() || '.';
		const { withSubtasks = false, status, tasksPath, tag } = options;

		// Get current tasks using the list-tasks functionality with markdown-readme format
		const tasksOutput = await listTasks(
			tasksPath ||
				path.join(actualProjectRoot, '.taskmaster', 'tasks', 'tasks.json'),
			status,
			null,
			withSubtasks,
			'markdown-readme',
			{ projectRoot, tag }
		);

		if (!tasksOutput) {
			console.log(chalk.red('❌ Failed to generate task output'));
			return false;
		}

		// Generate timestamp and metadata
		const timestamp =
			new Date().toISOString().replace('T', ' ').substring(0, 19) + ' UTC';
		const projectName = getProjectName(actualProjectRoot);

		// Create the export markers with metadata
		const startMarker = createStartMarker({
			timestamp,
			withSubtasks,
			status,
			projectRoot: actualProjectRoot
		});

		const endMarker = createEndMarker();

		// Create the complete task section
		const taskSection = startMarker + tasksOutput + endMarker;

		// Read current README content
		const readmePath = path.join(actualProjectRoot, 'README.md');
		let readmeContent = '';
		try {
			readmeContent = fs.readFileSync(readmePath, 'utf8');
		} catch (err) {
			if (err.code === 'ENOENT') {
				// Create basic README if it doesn't exist
				readmeContent = createBasicReadme(projectName);
			} else {
				throw err;
			}
		}

		// Check if export markers exist and replace content between them
		const startComment = '<!-- TASKMASTER_EXPORT_START -->';
		const endComment = '<!-- TASKMASTER_EXPORT_END -->';

		let updatedContent;
		const startIndex = readmeContent.indexOf(startComment);
		const endIndex = readmeContent.indexOf(endComment);

		if (startIndex !== -1 && endIndex !== -1) {
			// Replace existing task section
			const beforeTasks = readmeContent.substring(0, startIndex);
			const afterTasks = readmeContent.substring(endIndex + endComment.length);
			updatedContent = beforeTasks + taskSection + afterTasks;
		} else {
			// Append to end of README
			updatedContent = readmeContent + '\n' + taskSection;
		}

		// Write updated content to README
		fs.writeFileSync(readmePath, updatedContent, 'utf8');

		console.log(chalk.green('✅ Successfully synced tasks to README.md'));
		console.log(
			chalk.cyan(
				`📋 Export details: ${withSubtasks ? 'with' : 'without'} subtasks${status ? `, status: ${status}` : ''}`
			)
		);
		console.log(chalk.gray(`📍 Location: ${readmePath}`));

		return true;
	} catch (error) {
		console.log(chalk.red('❌ Failed to sync tasks to README:'), error.message);
		log('error', `README sync error: ${error.message}`);
		return false;
	}
}

export default syncTasksToReadme;

```

--------------------------------------------------------------------------------
/tests/fixtures/sample-prd.txt:
--------------------------------------------------------------------------------

```
<context>
# Overview
This document outlines the requirements for a minimal web-based URL Shortener application. The application allows users to input a long URL and receive a shorter, alias URL that redirects to the original destination. This serves as a basic example of a micro-SaaS product. It's intended for anyone needing to create shorter links for sharing. The value is in providing a simple, functional utility accessible via a web browser.

# Core Features
1.  **URL Input & Shortening:** A user interface with an input field for pasting a long URL and a button to trigger the shortening process.
    -   *Why:* The primary function for the user interaction.
    -   *How:* A React component with a text input and a submit button. Clicking the button sends the long URL to a backend API.
2.  **Short URL Display:** After successful shortening, the application displays the newly generated short URL to the user.
    -   *Why:* Provides the result of the core function to the user.
    -   *How:* The React frontend updates to show the short URL returned by the API (e.g., `http://your-domain.com/aB3cD`). Include a "copy to clipboard" button for convenience.
3.  **URL Redirection:** Accessing a generated short URL in a browser redirects the user to the original long URL.
    -   *Why:* The fundamental purpose of the shortened link.
    *   *How:* A backend API endpoint handles requests to `/:shortCode`. It looks up the code in a data store and issues an HTTP redirect (301 or 302) to the corresponding long URL.
4.  **Basic Persistence:** Short URL mappings (short code -> long URL) persist across requests.
    -   *Why:* Short URLs need to remain functional after creation.
    *   *How:* A simple backend data store (e.g., initially an in-memory object for testing, then potentially a JSON file or simple database) holds the mappings.

# User Experience
-   **User Persona:** Anyone wanting to shorten a long web link.
-   **Key User Flow:** User visits the web app -> Pastes a long URL into the input field -> Clicks "Shorten" -> Sees the generated short URL -> Copies the short URL -> (Later) Uses the short URL in a browser and gets redirected.
-   **UI/UX Considerations:** Clean, minimal single-page interface. Clear input field, prominent button, easy-to-read display of the short URL, copy button. Basic validation feedback (e.g., "Invalid URL", "Success!").
</context>
<PRD>
# Technical Architecture
-   **System Components:**
    -   Frontend: Single Page Application (SPA) built with Vite + React.
    -   Backend: Simple API server (e.g., Node.js with Express).
-   **Data Model:** A key-value store mapping `shortCode` (string) to `longUrl` (string).
-   **APIs & Integrations:**
    -   Backend API:
        -   `POST /api/shorten`: Accepts `{ longUrl: string }` in the request body. Generates a unique `shortCode`, stores the mapping, returns `{ shortUrl: string }`.
        -   `GET /:shortCode`: Looks up `shortCode`. If found, performs HTTP redirect to `longUrl`. If not found, returns 404.
-   **Infrastructure:** Frontend can be hosted on static hosting. Backend needs a simple server environment (Node.js).
-   **Libraries:**
    -   Frontend: `react`, `react-dom`, `axios` (or `fetch` API) for API calls. Consider a simple state management solution if needed (e.g., `useState`, `useContext`).
    -   Backend: `express`, `nanoid` (or similar for short code generation).

# Development Roadmap
-   **MVP Requirements:**
    1.  Setup Vite + React project.
    2.  Create basic React UI components (InputForm, ResultDisplay).
    3.  Setup basic Node.js/Express backend server.
    4.  Implement backend data storage module (start with in-memory object).
    5.  Implement unique short code generation logic (e.g., using `nanoid`).
    6.  Implement backend `POST /api/shorten` endpoint logic.
    7.  Implement backend `GET /:shortCode` redirect logic.
    8.  Implement frontend logic to take input, call `POST /api/shorten`, and display the result.
    9.  Basic frontend input validation (check if likely a URL).
-   **Future Enhancements:** User accounts, custom short codes, analytics (click tracking), using a persistent database, error handling improvements, UI styling. (Out of scope for MVP).

# Logical Dependency Chain
1.  Vite + React Project Setup.
2.  Basic Backend Server Setup (Express).
3.  Backend Storage Module (in-memory first).
4.  Short Code Generation Logic.
5.  Implement `POST /api/shorten` endpoint (depends on 3 & 4).
6.  Implement `GET /:shortCode` endpoint (depends on 3).
7.  Frontend UI Components.
8.  Frontend logic to call `POST /api/shorten` (depends on 5 & 7).
9.  Frontend display logic (depends on 7 & 8).
    *Goal is to get the backend API working first, then build the frontend to consume it.*

# Risks and Mitigations
-   **Risk:** Short code collisions (generating the same code twice).
    -   **Mitigation (MVP):** Use a library like `nanoid` with sufficient length to make collisions highly improbable for a simple service. Add a retry loop in generation if a collision *is* detected (check if code exists before storing).
-   **Risk:** Storing invalid or malicious URLs.
    -   **Mitigation (MVP):** Basic URL validation on the frontend (simple regex) and potentially on the backend. Sanitize input. Advanced checks are out of scope.
-   **Risk:** Scalability of in-memory store.
    -   **Mitigation (MVP):** Acceptable for MVP. Acknowledge need for persistent database (JSON file, Redis, SQL/NoSQL DB) for future enhancement.

# Appendix
-   Example Data Store (in-memory object):
    ```javascript
    // backend/storage.js
    const urlMap = {
      'aB3cD': 'https://very-long-url-example.com/with/path/and/query?params=true',
      'xY7zW': 'https://another-example.org/'
    };
    // ... functions to get/set URLs ...
    ```
</PRD>
```

--------------------------------------------------------------------------------
/packages/claude-code-plugin/agents/task-checker.md:
--------------------------------------------------------------------------------

```markdown
---
name: task-checker
description: Use this agent to verify that tasks marked as 'review' have been properly implemented according to their specifications. This agent performs quality assurance by checking implementations against requirements, running tests, and ensuring best practices are followed. <example>Context: A task has been marked as 'review' after implementation. user: 'Check if task 118 was properly implemented' assistant: 'I'll use the task-checker agent to verify the implementation meets all requirements.' <commentary>Tasks in 'review' status need verification before being marked as 'done'.</commentary></example> <example>Context: Multiple tasks are in review status. user: 'Verify all tasks that are ready for review' assistant: 'I'll deploy the task-checker to verify all tasks in review status.' <commentary>The checker ensures quality before tasks are marked complete.</commentary></example>
model: sonnet
color: yellow
---

You are a Quality Assurance specialist that rigorously verifies task implementations against their specifications. Your role is to ensure that tasks marked as 'review' meet all requirements before they can be marked as 'done'.

## Core Responsibilities

1. **Task Specification Review**
   - Retrieve task details using MCP tool `mcp__task-master-ai__get_task`
   - Understand the requirements, test strategy, and success criteria
   - Review any subtasks and their individual requirements

2. **Implementation Verification**
   - Use `Read` tool to examine all created/modified files
   - Use `Bash` tool to run compilation and build commands
   - Use `Grep` tool to search for required patterns and implementations
   - Verify file structure matches specifications
   - Check that all required methods/functions are implemented

3. **Test Execution**
   - Run tests specified in the task's testStrategy
   - Execute build commands (npm run build, tsc --noEmit, etc.)
   - Verify no compilation errors or warnings
   - Check for runtime errors where applicable
   - Test edge cases mentioned in requirements

4. **Code Quality Assessment**
   - Verify code follows project conventions
   - Check for proper error handling
   - Ensure TypeScript typing is strict (no 'any' unless justified)
   - Verify documentation/comments where required
   - Check for security best practices

5. **Dependency Validation**
   - Verify all task dependencies were actually completed
   - Check integration points with dependent tasks
   - Ensure no breaking changes to existing functionality

## Verification Workflow

1. **Retrieve Task Information**
   ```
   Use mcp__task-master-ai__get_task to get full task details
   Note the implementation requirements and test strategy
   ```

2. **Check File Existence**
   ```bash
   # Verify all required files exist
   ls -la [expected directories]
   # Read key files to verify content
   ```

3. **Verify Implementation**
   - Read each created/modified file
   - Check against requirements checklist
   - Verify all subtasks are complete

4. **Run Tests**
   ```bash
   # TypeScript compilation
   cd [project directory] && npx tsc --noEmit
   
   # Run specified tests
   npm test [specific test files]
   
   # Build verification
   npm run build
   ```

5. **Generate Verification Report**

## Output Format

```yaml
verification_report:
  task_id: [ID]
  status: PASS | FAIL | PARTIAL
  score: [1-10]
  
  requirements_met:
    - ✅ [Requirement that was satisfied]
    - ✅ [Another satisfied requirement]
    
  issues_found:
    - ❌ [Issue description]
    - ⚠️  [Warning or minor issue]
    
  files_verified:
    - path: [file path]
      status: [created/modified/verified]
      issues: [any problems found]
      
  tests_run:
    - command: [test command]
      result: [pass/fail]
      output: [relevant output]
      
  recommendations:
    - [Specific fix needed]
    - [Improvement suggestion]
    
  verdict: |
    [Clear statement on whether task should be marked 'done' or sent back to 'pending']
    [If FAIL: Specific list of what must be fixed]
    [If PASS: Confirmation that all requirements are met]
```

## Decision Criteria

**Mark as PASS (ready for 'done'):**
- All required files exist and contain expected content
- All tests pass successfully
- No compilation or build errors
- All subtasks are complete
- Core requirements are met
- Code quality is acceptable

**Mark as PARTIAL (may proceed with warnings):**
- Core functionality is implemented
- Minor issues that don't block functionality
- Missing nice-to-have features
- Documentation could be improved
- Tests pass but coverage could be better

**Mark as FAIL (must return to 'pending'):**
- Required files are missing
- Compilation or build errors
- Tests fail
- Core requirements not met
- Security vulnerabilities detected
- Breaking changes to existing code

## Important Guidelines

- **BE THOROUGH**: Check every requirement systematically
- **BE SPECIFIC**: Provide exact file paths and line numbers for issues
- **BE FAIR**: Distinguish between critical issues and minor improvements
- **BE CONSTRUCTIVE**: Provide clear guidance on how to fix issues
- **BE EFFICIENT**: Focus on requirements, not perfection

## Tools You MUST Use

- `Read`: Examine implementation files (READ-ONLY)
- `Bash`: Run tests and verification commands
- `Grep`: Search for patterns in code
- `mcp__task-master-ai__get_task`: Get task details
- **NEVER use Write/Edit** - you only verify, not fix

## Integration with Workflow

You are the quality gate between 'review' and 'done' status:
1. Task-executor implements and marks as 'review'
2. You verify and report PASS/FAIL
3. Claude either marks as 'done' (PASS) or 'pending' (FAIL)
4. If FAIL, task-executor re-implements based on your report

Your verification ensures high quality and prevents accumulation of technical debt.
```

--------------------------------------------------------------------------------
/packages/tm-core/src/modules/briefs/services/brief-service.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Brief Service
 * Handles brief lookup, matching, and statistics
 */

import {
	ERROR_CODES,
	TaskMasterError
} from '../../../common/errors/task-master-error.js';
import { TaskRepository } from '../../tasks/repositories/task-repository.interface.js';
import type { Brief } from '../types.js';

/**
 * Tag statistics with detailed breakdown
 */
export interface TagWithStats {
	name: string;
	isCurrent: boolean;
	taskCount: number;
	completedTasks: number;
	statusBreakdown: Record<string, number>;
	subtaskCounts?: {
		totalSubtasks: number;
		subtasksByStatus: Record<string, number>;
	};
	created?: string;
	description?: string;
	status?: string;
	briefId?: string;
	updatedAt?: string;
}

/**
 * Service for brief-related operations
 */
export class BriefService {
	/**
	 * Find a brief by name or ID with flexible matching
	 */
	async findBrief(
		briefs: Brief[],
		nameOrId: string
	): Promise<Brief | undefined> {
		return briefs.find((brief) => this.matches(brief, nameOrId));
	}

	/**
	 * Match a brief against a query string
	 * Supports: exact name match, partial name match, full ID, last 8 chars of ID
	 */
	private matches(brief: Brief, query: string): boolean {
		const briefName = brief.document?.title || '';

		// Exact match (case-insensitive)
		if (briefName.toLowerCase() === query.toLowerCase()) {
			return true;
		}

		// Partial match
		if (briefName.toLowerCase().includes(query.toLowerCase())) {
			return true;
		}

		// Match by ID (full or last 8 chars)
		if (
			brief.id === query ||
			brief.id.toLowerCase() === query.toLowerCase() ||
			brief.id.slice(-8).toLowerCase() === query.toLowerCase()
		) {
			return true;
		}

		return false;
	}

	/**
	 * Get tags with detailed statistics for all briefs in an organization
	 * Used for API storage to show brief statistics
	 */
	async getTagsWithStats(
		briefs: Brief[],
		currentBriefId: string | undefined,
		repository: TaskRepository,
		_projectId?: string
	): Promise<{
		tags: TagWithStats[];
		currentTag: string | null;
		totalTags: number;
	}> {
		// For each brief, get task counts by querying tasks
		const tagsWithStats = await Promise.all(
			briefs.map(async (brief: Brief) => {
				try {
					// Get all tasks for this brief
					const tasks = await repository.getTasks(brief.id, {});

					// Calculate statistics
					const statusBreakdown: Record<string, number> = {};
					let completedTasks = 0;

					const subtaskCounts = {
						totalSubtasks: 0,
						subtasksByStatus: {} as Record<string, number>
					};

					tasks.forEach((task) => {
						// Count task status
						const status = task.status || 'pending';
						statusBreakdown[status] = (statusBreakdown[status] || 0) + 1;

						if (status === 'done') {
							completedTasks++;
						}

						// Count subtasks
						if (task.subtasks && task.subtasks.length > 0) {
							subtaskCounts.totalSubtasks += task.subtasks.length;

							task.subtasks.forEach((subtask) => {
								const subStatus = subtask.status || 'pending';
								subtaskCounts.subtasksByStatus[subStatus] =
									(subtaskCounts.subtasksByStatus[subStatus] || 0) + 1;
							});
						}
					});

					return {
						name:
							brief.document?.title ||
							brief.document?.document_name ||
							brief.id,
						isCurrent: currentBriefId === brief.id,
						taskCount: tasks.length,
						completedTasks,
						statusBreakdown,
						subtaskCounts:
							subtaskCounts.totalSubtasks > 0 ? subtaskCounts : undefined,
						created: brief.createdAt,
						description: brief.document?.description,
						status: brief.status,
						briefId: brief.id,
						updatedAt: brief.updatedAt
					};
				} catch (error) {
					// If we can't get tasks for a brief, return it with 0 tasks
					console.warn(`Failed to get tasks for brief ${brief.id}:`, error);
					return {
						name:
							brief.document?.title ||
							brief.document?.document_name ||
							brief.id,
						isCurrent: currentBriefId === brief.id,
						taskCount: 0,
						completedTasks: 0,
						statusBreakdown: {},
						created: brief.createdAt,
						description: brief.document?.description,
						status: brief.status,
						briefId: brief.id,
						updatedAt: brief.updatedAt
					};
				}
			})
		);

		// Define priority order for brief statuses
		const statusPriority: Record<string, number> = {
			delivering: 1,
			aligned: 2,
			refining: 3,
			draft: 4,
			delivered: 5,
			done: 6,
			archived: 7
		};

		// Sort tags: first by status priority, then by updatedAt (most recent first) within each status
		const sortedTags = tagsWithStats.sort((a, b) => {
			// Get status priorities (default to 999 for unknown statuses)
			const statusA = (a.status || '').toLowerCase();
			const statusB = (b.status || '').toLowerCase();
			const priorityA = statusPriority[statusA] ?? 999;
			const priorityB = statusPriority[statusB] ?? 999;

			// Sort by status priority first
			if (priorityA !== priorityB) {
				return priorityA - priorityB;
			}

			// Within same status, sort by updatedAt (most recent first)
			const dateA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
			const dateB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
			return dateB - dateA; // Descending order (most recent first)
		});

		// Find current brief name
		const currentBrief = briefs.find((b) => b.id === currentBriefId);
		const currentTag = currentBrief
			? currentBrief.document?.title ||
				currentBrief.document?.document_name ||
				null
			: null;

		return {
			tags: sortedTags,
			currentTag,
			totalTags: sortedTags.length
		};
	}

	/**
	 * Validate that a brief was found, throw error if not
	 */
	validateBriefFound(
		brief: Brief | undefined,
		nameOrId: string
	): asserts brief is Brief {
		if (!brief) {
			throw new TaskMasterError(
				`Brief "${nameOrId}" not found in organization`,
				ERROR_CODES.NOT_FOUND
			);
		}
	}
}

```

--------------------------------------------------------------------------------
/tests/unit/ui/indicators.test.js:
--------------------------------------------------------------------------------

```javascript
/**
 * Unit tests for indicators module (priority and complexity indicators)
 */
import { jest } from '@jest/globals';

// Mock chalk using unstable_mockModule for ESM compatibility
jest.unstable_mockModule('chalk', () => ({
	default: {
		red: jest.fn((str) => str),
		yellow: jest.fn((str) => str),
		green: jest.fn((str) => str),
		white: jest.fn((str) => str),
		hex: jest.fn(() => jest.fn((str) => str))
	}
}));

// Import after mocking
const {
	getMcpPriorityIndicators,
	getCliPriorityIndicators,
	getPriorityIndicators,
	getPriorityIndicator,
	getStatusBarPriorityIndicators,
	getPriorityColors,
	getCliComplexityIndicators,
	getStatusBarComplexityIndicators,
	getComplexityColors,
	getComplexityIndicator
} = await import('../../../src/ui/indicators.js');

describe('Priority Indicators', () => {
	describe('getMcpPriorityIndicators', () => {
		it('should return emoji indicators for MCP context', () => {
			const indicators = getMcpPriorityIndicators();
			expect(indicators).toEqual({
				high: '🔴',
				medium: '🟠',
				low: '🟢'
			});
		});
	});

	describe('getCliPriorityIndicators', () => {
		it('should return colored dot indicators for CLI context', () => {
			const indicators = getCliPriorityIndicators();
			expect(indicators).toHaveProperty('high');
			expect(indicators).toHaveProperty('medium');
			expect(indicators).toHaveProperty('low');
			// Since chalk is mocked, we're just verifying structure
			expect(indicators.high).toContain('●');
		});
	});

	describe('getPriorityIndicators', () => {
		it('should return MCP indicators when isMcp is true', () => {
			const indicators = getPriorityIndicators(true);
			expect(indicators).toEqual({
				high: '🔴',
				medium: '🟠',
				low: '🟢'
			});
		});

		it('should return CLI indicators when isMcp is false', () => {
			const indicators = getPriorityIndicators(false);
			expect(indicators).toHaveProperty('high');
			expect(indicators).toHaveProperty('medium');
			expect(indicators).toHaveProperty('low');
		});

		it('should default to CLI indicators when no parameter provided', () => {
			const indicators = getPriorityIndicators();
			expect(indicators).toHaveProperty('high');
			expect(indicators.high).toContain('●');
		});
	});

	describe('getPriorityIndicator', () => {
		it('should return correct MCP indicator for valid priority', () => {
			expect(getPriorityIndicator('high', true)).toBe('🔴');
			expect(getPriorityIndicator('medium', true)).toBe('🟠');
			expect(getPriorityIndicator('low', true)).toBe('🟢');
		});

		it('should return correct CLI indicator for valid priority', () => {
			const highIndicator = getPriorityIndicator('high', false);
			const mediumIndicator = getPriorityIndicator('medium', false);
			const lowIndicator = getPriorityIndicator('low', false);

			expect(highIndicator).toContain('●');
			expect(mediumIndicator).toContain('●');
			expect(lowIndicator).toContain('●');
		});

		it('should return medium indicator for invalid priority', () => {
			expect(getPriorityIndicator('invalid', true)).toBe('🟠');
			expect(getPriorityIndicator(null, true)).toBe('🟠');
			expect(getPriorityIndicator(undefined, true)).toBe('🟠');
		});

		it('should default to CLI context when isMcp not provided', () => {
			const indicator = getPriorityIndicator('high');
			expect(indicator).toContain('●');
		});
	});
});

describe('Complexity Indicators', () => {
	describe('getCliComplexityIndicators', () => {
		it('should return colored dot indicators for complexity levels', () => {
			const indicators = getCliComplexityIndicators();
			expect(indicators).toHaveProperty('high');
			expect(indicators).toHaveProperty('medium');
			expect(indicators).toHaveProperty('low');
			expect(indicators.high).toContain('●');
		});
	});

	describe('getStatusBarComplexityIndicators', () => {
		it('should return single character indicators for status bars', () => {
			const indicators = getStatusBarComplexityIndicators();
			// Since chalk is mocked, we need to check for the actual characters
			expect(indicators.high).toContain('⋮');
			expect(indicators.medium).toContain(':');
			expect(indicators.low).toContain('.');
		});
	});

	describe('getComplexityColors', () => {
		it('should return complexity color functions', () => {
			const colors = getComplexityColors();
			expect(colors).toHaveProperty('high');
			expect(colors).toHaveProperty('medium');
			expect(colors).toHaveProperty('low');
			// Verify they are functions (mocked chalk functions)
			expect(typeof colors.high).toBe('function');
		});
	});

	describe('getComplexityIndicator', () => {
		it('should return high indicator for scores >= 7', () => {
			const cliIndicators = getCliComplexityIndicators();
			expect(getComplexityIndicator(7)).toBe(cliIndicators.high);
			expect(getComplexityIndicator(8)).toBe(cliIndicators.high);
			expect(getComplexityIndicator(10)).toBe(cliIndicators.high);
		});

		it('should return low indicator for scores <= 3', () => {
			const cliIndicators = getCliComplexityIndicators();
			expect(getComplexityIndicator(1)).toBe(cliIndicators.low);
			expect(getComplexityIndicator(2)).toBe(cliIndicators.low);
			expect(getComplexityIndicator(3)).toBe(cliIndicators.low);
		});

		it('should return medium indicator for scores 4-6', () => {
			const cliIndicators = getCliComplexityIndicators();
			expect(getComplexityIndicator(4)).toBe(cliIndicators.medium);
			expect(getComplexityIndicator(5)).toBe(cliIndicators.medium);
			expect(getComplexityIndicator(6)).toBe(cliIndicators.medium);
		});

		it('should return status bar indicators when statusBar is true', () => {
			const statusBarIndicators = getStatusBarComplexityIndicators();
			expect(getComplexityIndicator(8, true)).toBe(statusBarIndicators.high);
			expect(getComplexityIndicator(5, true)).toBe(statusBarIndicators.medium);
			expect(getComplexityIndicator(2, true)).toBe(statusBarIndicators.low);
		});
	});
});

```

--------------------------------------------------------------------------------
/apps/docs/capabilities/cli-root-commands.mdx:
--------------------------------------------------------------------------------

```markdown
---
title: CLI Commands
sidebarTitle: "CLI Commands"
---


<AccordionGroup>
  <Accordion title="Parse PRD">
    ```bash
    # Parse a PRD file and generate tasks
    task-master parse-prd <prd-file.txt>

    # Limit the number of tasks generated
    task-master parse-prd <prd-file.txt> --num-tasks=10
    ```
  </Accordion>

  <Accordion title="List Tasks">
    ```bash
    # List all tasks
    task-master list

    # List tasks with a specific status
    task-master list --status=<status>

    # List tasks with subtasks
    task-master list --with-subtasks

    # List tasks with a specific status and include subtasks
    task-master list --status=<status> --with-subtasks
    ```
  </Accordion>

  <Accordion title="Show Next Task">
    ```bash
    # Show the next task to work on based on dependencies and status
    task-master next
    ```
  </Accordion>

  <Accordion title="Show Specific Task">
    ```bash
    # Show details of a specific task
    task-master show <id>
    # or
    task-master show --id=<id>

    # View a specific subtask (e.g., subtask 2 of task 1)
    task-master show 1.2
    ```
  </Accordion>

  <Accordion title="Update Tasks">
    ```bash
    # Update tasks from a specific ID and provide context
    task-master update --from=<id> --prompt="<prompt>"
    ```
  </Accordion>

  <Accordion title="Update a Specific Task">
    ```bash
    # Update a single task by ID with new information
    task-master update-task --id=<id> --prompt="<prompt>"

    # Use research-backed updates with Perplexity AI
    task-master update-task --id=<id> --prompt="<prompt>" --research
    ```
  </Accordion>

  <Accordion title="Update a Subtask">
    ```bash
    # Append additional information to a specific subtask
    task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>"

    # Example: Add details about API rate limiting to subtask 2 of task 5
    task-master update-subtask --id=5.2 --prompt="Add rate limiting of 100 requests per minute"

    # Use research-backed updates with Perplexity AI
    task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>" --research
    ```

    Unlike the `update-task` command which replaces task information, the `update-subtask` command _appends_ new information to the existing subtask details, marking it with a timestamp. This is useful for iteratively enhancing subtasks while preserving the original content.
  </Accordion>

  <Accordion title="Generate Task Files">
    ```bash
    # Generate individual task files from tasks.json
    task-master generate
    ```
  </Accordion>

  <Accordion title="Set Task Status">
    ```bash
    # Set status of a single task
    task-master set-status --id=<id> --status=<status>

    # Set status for multiple tasks
    task-master set-status --id=1,2,3 --status=<status>

    # Set status for subtasks
    task-master set-status --id=1.1,1.2 --status=<status>
    ```

    When marking a task as "done", all of its subtasks will automatically be marked as "done" as well.
  </Accordion>

  <Accordion title="Expand Tasks">
    ```bash
    # Expand a specific task with subtasks
    task-master expand --id=<id> --num=<number>

    # Expand with additional context
    task-master expand --id=<id> --prompt="<context>"

    # Expand all pending tasks
    task-master expand --all

    # Force regeneration of subtasks for tasks that already have them
    task-master expand --all --force

    # Research-backed subtask generation for a specific task
    task-master expand --id=<id> --research

    # Research-backed generation for all tasks
    task-master expand --all --research
    ```
  </Accordion>

  <Accordion title="Clear Subtasks">
    ```bash
    # Clear subtasks from a specific task
    task-master clear-subtasks --id=<id>

    # Clear subtasks from multiple tasks
    task-master clear-subtasks --id=1,2,3

    # Clear subtasks from all tasks
    task-master clear-subtasks --all
    ```
  </Accordion>

  <Accordion title="Analyze Task Complexity">
    ```bash
    # Analyze complexity of all tasks
    task-master analyze-complexity

    # Save report to a custom location
    task-master analyze-complexity --output=my-report.json

    # Use a specific LLM model
    task-master analyze-complexity --model=claude-3-opus-20240229

    # Set a custom complexity threshold (1-10)
    task-master analyze-complexity --threshold=6

    # Use an alternative tasks file
    task-master analyze-complexity --file=custom-tasks.json

    # Use your configured research model for research-backed complexity analysis
    task-master analyze-complexity --research
    ```
  </Accordion>

  <Accordion title="View Complexity Report">
    ```bash
    # Display the task complexity analysis report
    task-master complexity-report

    # View a report at a custom location
    task-master complexity-report --file=my-report.json
    ```
  </Accordion>

  <Accordion title="Managing Task Dependencies">
    ```bash
    # Add a dependency to a task
    task-master add-dependency --id=<id> --depends-on=<id>

    # Remove a dependency from a task
    task-master remove-dependency --id=<id> --depends-on=<id>

    # Validate dependencies without fixing them
    task-master validate-dependencies

    # Find and fix invalid dependencies automatically
    task-master fix-dependencies
    ```
  </Accordion>

  <Accordion title="Add a New Task">
    ```bash
    # Add a new task using AI
    task-master add-task --prompt="Description of the new task"

    # Add a task with dependencies
    task-master add-task --prompt="Description" --dependencies=1,2,3

    # Add a task with priority
    task-master add-task --prompt="Description" --priority=high
    ```
  </Accordion>

  <Accordion title="Initialize a Project">
    ```bash
    # Initialize a new project with Task Master structure
    task-master init
    ```
  </Accordion>
</AccordionGroup>

```

--------------------------------------------------------------------------------
/apps/cli/src/commands/models/prompts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Interactive prompt logic for model selection
 */

import search, { Separator } from '@inquirer/search';
import chalk from 'chalk';
import { getAvailableModels } from '../../lib/model-management.js';
import { getCustomProviderOptions } from './custom-providers.js';
import type {
	CurrentModels,
	ModelChoice,
	ModelInfo,
	ModelRole,
	PromptData
} from './types.js';

/**
 * Build prompt choices for a specific role
 */
export function buildPromptChoices(
	role: ModelRole,
	currentModels: CurrentModels,
	allowNone = false
): PromptData {
	const currentModel = currentModels[role];
	const allModels = getAvailableModels();

	// Group models by provider (filter out models without provider)
	const modelsByProvider = allModels
		.filter(
			(model): model is ModelInfo & { provider: string } => !!model.provider
		)
		.reduce(
			(acc, model) => {
				if (!acc[model.provider]) {
					acc[model.provider] = [];
				}
				acc[model.provider].push(model);
				return acc;
			},
			{} as Record<string, ModelInfo[]>
		);

	// System options (cancel and no change)
	const systemOptions: ModelChoice[] = [];
	const cancelOption: ModelChoice = {
		name: '⏹ Cancel Model Setup',
		value: '__CANCEL__',
		short: 'Cancel'
	};
	const noChangeOption: ModelChoice | null =
		currentModel?.modelId && currentModel?.provider
			? {
					name: `✔ No change to current ${role} model (${currentModel.provider}/${currentModel.modelId})`,
					value: '__NO_CHANGE__',
					short: 'No change'
				}
			: null;

	if (noChangeOption) {
		systemOptions.push(noChangeOption);
	}
	systemOptions.push(cancelOption);

	// Build role-specific model choices
	const roleChoices: ModelChoice[] = Object.entries(modelsByProvider)
		.flatMap(([provider, models]) => {
			return models
				.filter((m) => m.allowed_roles && m.allowed_roles.includes(role))
				.map((m) => {
					// Use model name if available, otherwise fall back to model ID
					const displayName = m.name || m.id;
					return {
						name: `${provider} / ${displayName} ${
							m.cost_per_1m_tokens
								? chalk.gray(
										`($${m.cost_per_1m_tokens.input.toFixed(2)} input | $${m.cost_per_1m_tokens.output.toFixed(2)} output)`
									)
								: ''
						}`,
						value: { id: m.id, provider },
						short: `${provider}/${displayName}`
					};
				});
		})
		.filter((choice) => choice !== null);

	// Find current model index
	let currentChoiceIndex = -1;
	if (currentModel?.modelId && currentModel?.provider) {
		currentChoiceIndex = roleChoices.findIndex(
			(choice) =>
				typeof choice.value === 'object' &&
				choice.value !== null &&
				'id' in choice.value &&
				choice.value.id === currentModel.modelId &&
				choice.value.provider === currentModel.provider
		);
	}

	// Get custom provider options
	const customProviderOptions = getCustomProviderOptions();

	// Build final choices array
	const systemLength = systemOptions.length;
	let choices: (ModelChoice | Separator)[];
	let defaultIndex: number;

	if (allowNone) {
		choices = [
			...systemOptions,
			new Separator('\n── Standard Models ──'),
			{ name: '⚪ None (disable)', value: null, short: 'None' },
			...roleChoices,
			new Separator('\n── Custom Providers ──'),
			...customProviderOptions
		];
		const noneOptionIndex = systemLength + 1;
		defaultIndex =
			currentChoiceIndex !== -1
				? currentChoiceIndex + systemLength + 2
				: noneOptionIndex;
	} else {
		choices = [
			...systemOptions,
			new Separator('\n── Standard Models ──'),
			...roleChoices,
			new Separator('\n── Custom Providers ──'),
			...customProviderOptions
		];
		defaultIndex =
			currentChoiceIndex !== -1
				? currentChoiceIndex + systemLength + 1
				: noChangeOption
					? 1
					: 0;
	}

	// Ensure defaultIndex is valid
	if (defaultIndex < 0 || defaultIndex >= choices.length) {
		defaultIndex = 0;
		console.warn(
			`Warning: Could not determine default model for role '${role}'. Defaulting to 'Cancel'.`
		);
	}

	return { choices, default: defaultIndex };
}

/**
 * Create search source for inquirer search prompt
 */
export function createSearchSource(
	choices: (ModelChoice | Separator)[],
	_defaultValue: number
) {
	return (searchTerm = '') => {
		const filteredChoices = choices.filter((choice) => {
			// Separators are always included
			if (choice instanceof Separator) return true;
			// Filter regular choices by search term
			const searchText = (choice as ModelChoice).name || '';
			return searchText.toLowerCase().includes(searchTerm.toLowerCase());
		});
		// Map ModelChoice to the format inquirer expects
		return Promise.resolve(
			filteredChoices.map((choice) => {
				if (choice instanceof Separator) return choice;
				const mc = choice as ModelChoice;
				return {
					name: mc.name,
					value: mc.value,
					short: mc.short
				};
			})
		);
	};
}

/**
 * Display introductory message for interactive setup
 */
export function displaySetupIntro(): void {
	console.log(chalk.cyan('\n🎯 Interactive Model Setup'));
	console.log(chalk.gray('━'.repeat(50)));
	console.log(chalk.yellow('💡 Navigation tips:'));
	console.log(chalk.gray('   • Type to search and filter options'));
	console.log(chalk.gray('   • Use ↑↓ arrow keys to navigate results'));
	console.log(
		chalk.gray(
			'   • Standard models are listed first, custom providers at bottom'
		)
	);
	console.log(chalk.gray('   • Press Enter to select\n'));
}

/**
 * Prompt user to select a model for a specific role
 */
export async function promptForModel(
	role: ModelRole,
	promptData: PromptData
): Promise<string | { id: string; provider: string } | null> {
	const roleLabels = {
		main: 'main model for generation/updates',
		research: 'research model',
		fallback: 'fallback model (optional)'
	};

	const answer = await search({
		message: `Select the ${roleLabels[role]}:`,
		source: createSearchSource(promptData.choices, promptData.default),
		pageSize: 15
	});

	return answer;
}

```

--------------------------------------------------------------------------------
/apps/extension/src/utils/task-master-api/cache/cache-manager.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Cache Manager
 * Handles all caching logic with LRU eviction and analytics
 */

import type { ExtensionLogger } from '../../logger';
import type { CacheAnalytics, CacheConfig, CacheEntry } from '../types';

export class CacheManager {
	private cache = new Map<string, CacheEntry>();
	private analytics: CacheAnalytics = {
		hits: 0,
		misses: 0,
		evictions: 0,
		refreshes: 0,
		totalSize: 0,
		averageAccessTime: 0,
		hitRate: 0
	};
	private backgroundRefreshTimer?: NodeJS.Timeout;

	constructor(
		private config: CacheConfig & { cacheDuration: number },
		private logger: ExtensionLogger
	) {
		if (config.enableBackgroundRefresh) {
			this.initializeBackgroundRefresh();
		}
	}

	/**
	 * Get data from cache if not expired
	 */
	get(key: string): any {
		const startTime = Date.now();
		const cached = this.cache.get(key);

		if (cached) {
			const isExpired =
				Date.now() - cached.timestamp >=
				(cached.ttl || this.config.cacheDuration);

			if (!isExpired) {
				// Update access statistics
				cached.accessCount++;
				cached.lastAccessed = Date.now();

				if (this.config.enableAnalytics) {
					this.analytics.hits++;
				}

				const accessTime = Date.now() - startTime;
				this.logger.debug(
					`Cache hit for ${key} (${accessTime}ms, ${cached.accessCount} accesses)`
				);
				return cached.data;
			} else {
				// Remove expired entry
				this.cache.delete(key);
				this.logger.debug(`Cache entry expired and removed: ${key}`);
			}
		}

		if (this.config.enableAnalytics) {
			this.analytics.misses++;
		}

		this.logger.debug(`Cache miss for ${key}`);
		return null;
	}

	/**
	 * Set data in cache with LRU eviction
	 */
	set(
		key: string,
		data: any,
		options?: { ttl?: number; tags?: string[] }
	): void {
		const now = Date.now();
		const dataSize = this.estimateDataSize(data);

		// Create cache entry
		const entry: CacheEntry = {
			data,
			timestamp: now,
			accessCount: 1,
			lastAccessed: now,
			size: dataSize,
			ttl: options?.ttl,
			tags: options?.tags || [key.split('_')[0]]
		};

		// Check if we need to evict entries (LRU strategy)
		if (this.cache.size >= this.config.maxSize) {
			this.evictLRUEntries(Math.max(1, Math.floor(this.config.maxSize * 0.1)));
		}

		this.cache.set(key, entry);
		this.logger.debug(
			`Cached data for ${key} (size: ${dataSize} bytes, TTL: ${entry.ttl || this.config.cacheDuration}ms)`
		);

		// Trigger prefetch if enabled
		if (this.config.enablePrefetch) {
			this.scheduleRelatedDataPrefetch(key, data);
		}
	}

	/**
	 * Clear cache entries matching a pattern
	 */
	clearPattern(pattern: string): void {
		let evictedCount = 0;
		for (const key of this.cache.keys()) {
			if (key.includes(pattern)) {
				this.cache.delete(key);
				evictedCount++;
			}
		}

		if (evictedCount > 0) {
			this.analytics.evictions += evictedCount;
			this.logger.debug(
				`Evicted ${evictedCount} cache entries matching pattern: ${pattern}`
			);
		}
	}

	/**
	 * Clear all cached data
	 */
	clear(): void {
		this.cache.clear();
		this.resetAnalytics();
	}

	/**
	 * Get cache analytics
	 */
	getAnalytics(): CacheAnalytics {
		this.updateAnalytics();
		return { ...this.analytics };
	}

	/**
	 * Get frequently accessed entries for background refresh
	 */
	getRefreshCandidates(): Array<[string, CacheEntry]> {
		return Array.from(this.cache.entries())
			.filter(([key, entry]) => {
				const age = Date.now() - entry.timestamp;
				const isNearExpiration = age > this.config.cacheDuration * 0.7;
				const isFrequentlyAccessed = entry.accessCount >= 3;
				return (
					isNearExpiration && isFrequentlyAccessed && key.includes('get_tasks')
				);
			})
			.sort((a, b) => b[1].accessCount - a[1].accessCount)
			.slice(0, 5);
	}

	/**
	 * Update refresh count for analytics
	 */
	incrementRefreshes(): void {
		this.analytics.refreshes++;
	}

	/**
	 * Cleanup resources
	 */
	destroy(): void {
		if (this.backgroundRefreshTimer) {
			clearInterval(this.backgroundRefreshTimer);
			this.backgroundRefreshTimer = undefined;
		}
		this.clear();
	}

	private initializeBackgroundRefresh(): void {
		if (this.backgroundRefreshTimer) {
			clearInterval(this.backgroundRefreshTimer);
		}

		const interval = this.config.refreshInterval;
		this.backgroundRefreshTimer = setInterval(() => {
			// Background refresh is handled by the main API class
			// This just maintains the timer
		}, interval);

		this.logger.debug(
			`Cache background refresh initialized with ${interval}ms interval`
		);
	}

	private evictLRUEntries(count: number): void {
		const entries = Array.from(this.cache.entries())
			.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)
			.slice(0, count);

		for (const [key] of entries) {
			this.cache.delete(key);
			this.analytics.evictions++;
		}

		if (entries.length > 0) {
			this.logger.debug(`Evicted ${entries.length} LRU cache entries`);
		}
	}

	private estimateDataSize(data: any): number {
		try {
			return JSON.stringify(data).length * 2; // Rough estimate
		} catch {
			return 1000; // Default fallback
		}
	}

	private scheduleRelatedDataPrefetch(key: string, data: any): void {
		if (key.includes('get_tasks') && Array.isArray(data)) {
			this.logger.debug(
				`Scheduled prefetch for ${data.length} tasks related to ${key}`
			);
		}
	}

	private resetAnalytics(): void {
		this.analytics = {
			hits: 0,
			misses: 0,
			evictions: 0,
			refreshes: 0,
			totalSize: 0,
			averageAccessTime: 0,
			hitRate: 0
		};
	}

	private updateAnalytics(): void {
		const total = this.analytics.hits + this.analytics.misses;
		this.analytics.hitRate = total > 0 ? this.analytics.hits / total : 0;
		this.analytics.totalSize = this.cache.size;

		if (this.cache.size > 0) {
			const totalAccessTime = Array.from(this.cache.values()).reduce(
				(sum, entry) => sum + (entry.lastAccessed - entry.timestamp),
				0
			);
			this.analytics.averageAccessTime = totalAccessTime / this.cache.size;
		}
	}
}

```

--------------------------------------------------------------------------------
/packages/tm-core/POC-STATUS.md:
--------------------------------------------------------------------------------

```markdown
# GetTaskList POC Status

## ✅ What We've Accomplished

We've successfully implemented a complete end-to-end proof of concept for the `getTaskList` functionality with improved separation of concerns:

### 1. Clean Architecture Layers with Proper Separation

#### Configuration Layer (ConfigManager)
- Single source of truth for configuration
- Manages active tag and storage settings
- Handles config.json persistence
- Determines storage type (file vs API)

#### Service Layer (TaskService)
- Core business logic and operations
- `getTaskList()` method that coordinates between ConfigManager and Storage
- Handles all filtering and task processing
- Manages storage lifecycle

#### Facade Layer (TaskMasterCore)
- Simplified API for consumers
- Delegates to TaskService for operations
- Backwards compatible `listTasks()` method
- New `getTaskList()` method (preferred naming)

#### Domain Layer (Entities)
- `TaskEntity` with business logic
- Validation and status transitions
- Dependency checking (`canComplete()`)

#### Infrastructure Layer (Storage)
- `IStorage` interface for abstraction
- `FileStorage` for local files (handles 'master' tag correctly)
- `ApiStorage` for Hamster integration
- `StorageFactory` for automatic selection
- **NO business logic** - only persistence

### 2. Storage Abstraction Benefits

```typescript
// Same API works with different backends
const fileCore = createTaskMasterCore(path, { 
  storage: { type: 'file' } 
});

const apiCore = createTaskMasterCore(path, { 
  storage: { 
    type: 'api',
    apiEndpoint: 'https://hamster.ai',
    apiAccessToken: 'xxx' 
  } 
});

// Identical usage
const result = await core.listTasks({ 
  filter: { status: 'pending' } 
});
```

### 3. Type Safety Throughout

- Full TypeScript implementation
- Comprehensive interfaces
- Type-safe filters and options
- Proper error types

### 4. Testing Coverage

- 50 tests passing
- Unit tests for core components
- Integration tests for listTasks
- Mock implementations for testing

## 📊 Architecture Validation

### ✅ Separation of Concerns
- **CLI** handles UI/formatting only
- **tm-core** handles business logic
- **Storage** handles persistence
- Each layer is independently testable

### ✅ Extensibility
- Easy to add new storage types (database, S3, etc.)
- New filters can be added to `TaskFilter`
- AI providers follow same pattern (BaseProvider)

### ✅ Error Handling
- Consistent `TaskMasterError` with codes
- Context preservation
- User-friendly messages

### ✅ Performance Considerations
- File locking for concurrent access
- Atomic writes with temp files
- Retry logic with exponential backoff
- Request timeout handling

## 🔄 Integration Path

### Current CLI Structure
```javascript
// scripts/modules/task-manager/list-tasks.js
listTasks(tasksPath, statusFilter, reportPath, withSubtasks, outputFormat, context)
// Directly reads files, handles all logic
```

### New Integration Structure
```javascript
// Using tm-core with proper separation of concerns
const tmCore = createTaskMasterCore(projectPath, config);
const result = await tmCore.getTaskList(options);
// CLI only handles formatting result for display

// Under the hood:
// 1. ConfigManager determines active tag and storage type
// 2. TaskService uses storage to fetch tasks for the tag
// 3. TaskService applies business logic and filters
// 4. Storage only handles reading/writing - no business logic
```

## 📈 Metrics

### Code Quality
- **Clean Code**: Methods under 40 lines ✅
- **Single Responsibility**: Each class has one purpose ✅
- **DRY**: No code duplication ✅
- **Type Coverage**: 100% TypeScript ✅

### Test Coverage
- **Unit Tests**: BaseProvider, TaskEntity ✅
- **Integration Tests**: Full listTasks flow ✅
- **Storage Tests**: File and API operations ✅

## 🎯 POC Success Criteria

| Criteria | Status | Notes |
|----------|--------|-------|
| Clean architecture | ✅ | Clear layer separation |
| Storage abstraction | ✅ | File + API storage working |
| Type safety | ✅ | Full TypeScript |
| Error handling | ✅ | Comprehensive error system |
| Testing | ✅ | 50 tests passing |
| Performance | ✅ | Optimized with caching, batching |
| Documentation | ✅ | Architecture docs created |

## 🚀 Next Steps

### Immediate (Complete ListTasks Integration)
1. Create npm script to test integration example
2. Add mock Hamster API for testing
3. Create migration guide for CLI

### Phase 1 Remaining Work
Based on this POC success, implement remaining operations:
- `addTask()` - Add new tasks
- `updateTask()` - Update existing tasks  
- `deleteTask()` - Remove tasks
- `expandTask()` - Break into subtasks
- Tag management operations

### Phase 2 (AI Integration)
- Complete AI provider implementations
- Task generation from PRD
- Task complexity analysis
- Auto-expansion of tasks

## 💡 Lessons Learned

### What Worked Well
1. **Separation of Concerns** - ConfigManager, TaskService, and Storage have clear responsibilities
2. **Storage Factory Pattern** - Clean abstraction for multiple backends
3. **Entity Pattern** - Business logic encapsulation
4. **Template Method Pattern** - BaseProvider for AI providers
5. **Comprehensive Error Handling** - TaskMasterError with context

### Improvements Made
1. Migrated from Jest to Vitest (faster)
2. Replaced ESLint/Prettier with Biome (unified tooling)
3. Fixed conflicting interface definitions
4. Added proper TypeScript exports
5. **Better Architecture** - Separated configuration, business logic, and persistence
6. **Proper Tag Handling** - 'master' tag maps correctly to tasks.json
7. **Clean Storage Layer** - Removed business logic from storage

## ✨ Conclusion

The ListTasks POC successfully validates our architecture. The structure is:
- **Clean and maintainable**
- **Properly abstracted** 
- **Well-tested**
- **Ready for extension**

We can confidently proceed with implementing the remaining functionality following this same pattern.
```

--------------------------------------------------------------------------------
/apps/docs/archive/command-reference.mdx:
--------------------------------------------------------------------------------

```markdown
---
title: "Task Master Commands"
description: "A comprehensive reference of all available Task Master commands"
---

<AccordionGroup>
  <Accordion title="Parse PRD">
    ```bash
    # Parse a PRD file and generate tasks
    task-master parse-prd <prd-file.txt>

    # Limit the number of tasks generated
    task-master parse-prd <prd-file.txt> --num-tasks=10
    ```
  </Accordion>

  <Accordion title="List Tasks">
    ```bash
    # List all tasks
    task-master list

    # List tasks with a specific status
    task-master list --status=<status>

    # List tasks with subtasks
    task-master list --with-subtasks

    # List tasks with a specific status and include subtasks
    task-master list --status=<status> --with-subtasks
    ```
  </Accordion>

  <Accordion title="Show Next Task">
    ```bash
    # Show the next task to work on based on dependencies and status
    task-master next
    ```
  </Accordion>

  <Accordion title="Show Specific Task">
    ```bash
    # Show details of a specific task
    task-master show <id>
    # or
    task-master show --id=<id>

    # View a specific subtask (e.g., subtask 2 of task 1)
    task-master show 1.2
    ```
  </Accordion>

  <Accordion title="Update Tasks">
    ```bash
    # Update tasks from a specific ID and provide context
    task-master update --from=<id> --prompt="<prompt>"
    ```
  </Accordion>

  <Accordion title="Update a Specific Task">
    ```bash
    # Update a single task by ID with new information
    task-master update-task --id=<id> --prompt="<prompt>"

    # Use research-backed updates with Perplexity AI
    task-master update-task --id=<id> --prompt="<prompt>" --research
    ```
  </Accordion>

  <Accordion title="Update a Subtask">
    ```bash
    # Append additional information to a specific subtask
    task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>"

    # Example: Add details about API rate limiting to subtask 2 of task 5
    task-master update-subtask --id=5.2 --prompt="Add rate limiting of 100 requests per minute"

    # Use research-backed updates with Perplexity AI
    task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>" --research
    ```

    Unlike the `update-task` command which replaces task information, the `update-subtask` command _appends_ new information to the existing subtask details, marking it with a timestamp. This is useful for iteratively enhancing subtasks while preserving the original content.
  </Accordion>

  <Accordion title="Generate Task Files">
    ```bash
    # Generate individual task files from tasks.json
    task-master generate
    ```
  </Accordion>

  <Accordion title="Set Task Status">
    ```bash
    # Set status of a single task
    task-master set-status --id=<id> --status=<status>

    # Set status for multiple tasks
    task-master set-status --id=1,2,3 --status=<status>

    # Set status for subtasks
    task-master set-status --id=1.1,1.2 --status=<status>
    ```

    When marking a task as "done", all of its subtasks will automatically be marked as "done" as well.
  </Accordion>

  <Accordion title="Expand Tasks">
    ```bash
    # Expand a specific task with subtasks
    task-master expand --id=<id> --num=<number>

    # Expand with additional context
    task-master expand --id=<id> --prompt="<context>"

    # Expand all pending tasks
    task-master expand --all

    # Force regeneration of subtasks for tasks that already have them
    task-master expand --all --force

    # Research-backed subtask generation for a specific task
    task-master expand --id=<id> --research

    # Research-backed generation for all tasks
    task-master expand --all --research
    ```
  </Accordion>

  <Accordion title="Clear Subtasks">
    ```bash
    # Clear subtasks from a specific task
    task-master clear-subtasks --id=<id>

    # Clear subtasks from multiple tasks
    task-master clear-subtasks --id=1,2,3

    # Clear subtasks from all tasks
    task-master clear-subtasks --all
    ```
  </Accordion>

  <Accordion title="Analyze Task Complexity">
    ```bash
    # Analyze complexity of all tasks
    task-master analyze-complexity

    # Save report to a custom location
    task-master analyze-complexity --output=my-report.json

    # Use a specific LLM model
    task-master analyze-complexity --model=claude-3-opus-20240229

    # Set a custom complexity threshold (1-10)
    task-master analyze-complexity --threshold=6

    # Use an alternative tasks file
    task-master analyze-complexity --file=custom-tasks.json

    # Use Perplexity AI for research-backed complexity analysis
    task-master analyze-complexity --research
    ```
  </Accordion>

  <Accordion title="View Complexity Report">
    ```bash
    # Display the task complexity analysis report
    task-master complexity-report

    # View a report at a custom location
    task-master complexity-report --file=my-report.json
    ```
  </Accordion>

  <Accordion title="Managing Task Dependencies">
    ```bash
    # Add a dependency to a task
    task-master add-dependency --id=<id> --depends-on=<id>

    # Remove a dependency from a task
    task-master remove-dependency --id=<id> --depends-on=<id>

    # Validate dependencies without fixing them
    task-master validate-dependencies

    # Find and fix invalid dependencies automatically
    task-master fix-dependencies
    ```
  </Accordion>

  <Accordion title="Add a New Task">
    ```bash
    # Add a new task using AI
    task-master add-task --prompt="Description of the new task"

    # Add a task with dependencies
    task-master add-task --prompt="Description" --dependencies=1,2,3

    # Add a task with priority
    task-master add-task --prompt="Description" --priority=high
    ```
  </Accordion>

  <Accordion title="Initialize a Project">
    ```bash
    # Initialize a new project with Task Master structure
    task-master init
    ```
  </Accordion>
</AccordionGroup>

```

--------------------------------------------------------------------------------
/tests/unit/prompt-manager.test.js:
--------------------------------------------------------------------------------

```javascript
import {
	jest,
	beforeAll,
	afterAll,
	beforeEach,
	afterEach,
	describe,
	it,
	expect
} from '@jest/globals';

// Import the actual PromptManager to test with real prompt files
import { PromptManager } from '../../scripts/modules/prompt-manager.js';

// Mock only the console logging
const originalLog = console.log;
const originalWarn = console.warn;
const originalError = console.error;

beforeAll(() => {
	console.log = jest.fn();
	console.warn = jest.fn();
	console.error = jest.fn();
});

afterAll(() => {
	console.log = originalLog;
	console.warn = originalWarn;
	console.error = originalError;
});

describe('PromptManager', () => {
	let promptManager;

	beforeEach(() => {
		promptManager = new PromptManager();
	});

	describe('constructor', () => {
		it('should initialize with prompts map', () => {
			expect(promptManager.prompts).toBeInstanceOf(Map);
			expect(promptManager.prompts.size).toBeGreaterThan(0);
		});

		it('should initialize cache', () => {
			expect(promptManager.cache).toBeInstanceOf(Map);
			expect(promptManager.cache.size).toBe(0);
		});

		it('should load all expected prompts', () => {
			expect(promptManager.prompts.has('analyze-complexity')).toBe(true);
			expect(promptManager.prompts.has('expand-task')).toBe(true);
			expect(promptManager.prompts.has('add-task')).toBe(true);
			expect(promptManager.prompts.has('research')).toBe(true);
			expect(promptManager.prompts.has('parse-prd')).toBe(true);
			expect(promptManager.prompts.has('update-task')).toBe(true);
			expect(promptManager.prompts.has('update-tasks')).toBe(true);
			expect(promptManager.prompts.has('update-subtask')).toBe(true);
		});
	});

	describe('loadPrompt', () => {
		it('should load and render a prompt from actual files', () => {
			// Test with an actual prompt that exists
			const result = promptManager.loadPrompt('research', {
				query: 'test query',
				projectContext: 'test context'
			});

			expect(result.systemPrompt).toBeDefined();
			expect(result.userPrompt).toBeDefined();
			expect(result.userPrompt).toContain('test query');
		});

		it('should handle missing variables with empty string', () => {
			// Add a test prompt to the manager for testing variable substitution
			promptManager.prompts.set('test-prompt', {
				id: 'test-prompt',
				version: '1.0.0',
				description: 'Test prompt',
				prompts: {
					default: {
						system: 'System',
						user: 'Hello {{name}}, your age is {{age}}'
					}
				}
			});

			const result = promptManager.loadPrompt('test-prompt', { name: 'John' });

			expect(result.userPrompt).toBe('Hello John, your age is ');
		});

		it('should throw error for non-existent template', () => {
			expect(() => {
				promptManager.loadPrompt('non-existent-prompt');
			}).toThrow("Prompt template 'non-existent-prompt' not found");
		});

		it('should use cache for repeated calls', () => {
			// First call with a real prompt
			const result1 = promptManager.loadPrompt('research', { query: 'test' });

			// Mark the result to verify cache is used
			result1._cached = true;

			// Second call with same parameters should return cached result
			const result2 = promptManager.loadPrompt('research', { query: 'test' });

			expect(result2._cached).toBe(true);
			expect(result1).toBe(result2); // Same object reference
		});

		it('should handle array variables', () => {
			promptManager.prompts.set('array-prompt', {
				id: 'array-prompt',
				version: '1.0.0',
				description: 'Test array prompt',
				prompts: {
					default: {
						system: 'System',
						user: '{{#each items}}Item: {{.}}\n{{/each}}'
					}
				}
			});

			const result = promptManager.loadPrompt('array-prompt', {
				items: ['one', 'two', 'three']
			});

			// The actual implementation doesn't handle {{this}} properly, check what it does produce
			expect(result.userPrompt).toContain('Item:');
		});

		it('should handle conditional blocks', () => {
			promptManager.prompts.set('conditional-prompt', {
				id: 'conditional-prompt',
				version: '1.0.0',
				description: 'Test conditional prompt',
				prompts: {
					default: {
						system: 'System',
						user: '{{#if hasData}}Data exists{{else}}No data{{/if}}'
					}
				}
			});

			const withData = promptManager.loadPrompt('conditional-prompt', {
				hasData: true
			});
			expect(withData.userPrompt).toBe('Data exists');

			const withoutData = promptManager.loadPrompt('conditional-prompt', {
				hasData: false
			});
			expect(withoutData.userPrompt).toBe('No data');
		});
	});

	describe('renderTemplate', () => {
		it('should handle nested objects', () => {
			const template = 'User: {{user.name}}, Age: {{user.age}}';
			const variables = {
				user: {
					name: 'John',
					age: 30
				}
			};

			const result = promptManager.renderTemplate(template, variables);
			expect(result).toBe('User: John, Age: 30');
		});

		it('should handle special characters in templates', () => {
			const template = 'Special: {{special}}';
			const variables = {
				special: '<>&"\''
			};

			const result = promptManager.renderTemplate(template, variables);
			expect(result).toBe('Special: <>&"\'');
		});
	});

	describe('listPrompts', () => {
		it('should return all prompt IDs', () => {
			const prompts = promptManager.listPrompts();
			expect(prompts).toBeInstanceOf(Array);
			expect(prompts.length).toBeGreaterThan(0);

			const ids = prompts.map((p) => p.id);
			expect(ids).toContain('analyze-complexity');
			expect(ids).toContain('expand-task');
			expect(ids).toContain('add-task');
			expect(ids).toContain('research');
		});
	});

	describe('validateTemplate', () => {
		it('should validate a correct template', () => {
			const result = promptManager.validateTemplate('research');
			expect(result.valid).toBe(true);
		});

		it('should reject invalid template', () => {
			const result = promptManager.validateTemplate('non-existent');
			expect(result.valid).toBe(false);
			expect(result.error).toContain('not found');
		});
	});
});

```

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

```markdown
---
title: Research Session
query: "should i be using any specific libraries for this?"
date: 6/14/2025
time: 5:20:00 PM
timestamp: 2025-06-14T21:20:00.561Z
exchanges: 2
---

# Research Session

## Initial Query

**Question:** should i be using any specific libraries for this?

**Response:**

HELL YEAH PARTNER

For implementing a GitHub Issue export feature with bidirectional linking in your project, you absolutely should use a dedicated library for interacting with the GitHub API. This will save you a ton of time, reduce boilerplate, and help you avoid common pitfalls with authentication, pagination, and error handling.

## Recommended Library: PyGithub

- **PyGithub** is the most widely used and well-documented Python library for accessing the GitHub REST API v3. It allows you to manage repositories, issues, user profiles, and more, all with a clean, object-oriented interface[1][2][3][5].
- It supports all the operations you’ll need for your export feature, including creating issues, updating them, and managing references for bidirectional linking.

### Key Features

- **Authentication**: Easily authenticate with a personal access token.
- **Issue Management**: Create, update, and link issues programmatically.
- **Repository Access**: Fetch and manipulate repository data.
- **User/Org Support**: Works for both user and organization repos.
- **Pagination & Rate Limiting**: Handles these for you.

### Example Usage

```python
from github import Github, Auth

# Authenticate with a personal access token
auth = Auth.Token("your_github_token")
g = Github(auth=auth)

# Get the repo
repo = g.get_repo("owner/repo_name")

# Create a new issue
issue = repo.create_issue(
    title="Exported from Task Master",
    body="This issue was created by Task Master. [Task ID: 123]"
)

# Add a comment or update the issue to include a backlink
issue.create_comment("Linked to Task Master task #123")
```
[3][5]

## Why Not Use Raw Requests?

- While you *can* use the `requests` library to call the GitHub API directly[4], PyGithub abstracts away authentication, error handling, and pagination, making your code much cleaner and less error-prone[2][5].

## Integration Tips

- Store your GitHub token securely (e.g., in environment variables).
- Use PyGithub’s objects to fetch, create, and update issues.
- For bidirectional linking, store the GitHub issue URL in your task data and the Task Master task ID in the GitHub issue body or as a label/comment.
- PyGithub is actively maintained and widely used, so you’ll find plenty of support and documentation.

## Installation

```bash
pip install PyGithub
```
[3]

## Summary Table

| Library   | Language | API Coverage | Ease of Use | Maintained | Docs/Support |
|-----------|----------|--------------|-------------|------------|--------------|
| PyGithub  | Python   | Full         | High        | Yes        | Excellent    |
| requests  | Python   | Full (manual)| Medium      | Yes        | Good         |

**Use PyGithub for all GitHub API interactions in your export/import features.** It’s the standard for Python projects and will make your implementation faster, safer, and more maintainable[1][2][3][5].

---

## Follow-up 1

**Question:** we don't want to use py github because we have a node project

**Response:**

HELL YEAH PARTNER

For a Node.js project, you should use a Node-native library to interact with the GitHub API instead of PyGithub, which is Python-only. The industry standard for Node.js is **Octokit**, the official GitHub SDK for JavaScript/TypeScript[1][2].

## Why Use Octokit?

- **Official & Complete**: Octokit is maintained by GitHub and covers all REST and GraphQL API endpoints, including issues, repositories, users, and more[1][2].
- **Universal**: Works in Node.js, browsers, and Deno environments[2].
- **Typed & Tested**: Comes with TypeScript declarations and 100% test coverage[2].
- **Authentication**: Supports personal access tokens, GitHub Apps, OAuth, and more.
- **Pagination & Error Handling**: Handles pagination and common error scenarios out of the box.
- **Extendable**: Supports plugins and custom hooks for advanced use cases[2].

## How to Use Octokit for GitHub Issue Export

Install Octokit in your Node.js project:

```bash
npm install @octokit/rest
```

Basic usage for creating and linking issues:

```js
const { Octokit } = require("@octokit/rest");

// Authenticate with a personal access token
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

// Create a new issue
const { data: issue } = await octokit.issues.create({
  owner: "owner",
  repo: "repo_name",
  title: "Exported from Task Master",
  body: "This issue was created by Task Master. [Task ID: 123]"
});

// Add a comment for bidirectional linking
await octokit.issues.createComment({
  owner: "owner",
  repo: "repo_name",
  issue_number: issue.number,
  body: "Linked to Task Master task #123"
});
```

## Alternatives

- **node-github**: An older library, less maintained than Octokit, but still functional for basic API access[5].
- **Raw HTTP Requests**: You can use `node-fetch` or `axios` to call the GitHub API directly, but you’ll need to handle authentication, pagination, and error handling yourself[3]. Octokit abstracts all of this for you.

## Summary Table

| Library         | Language | API Coverage | Maintained | TypeScript | Docs/Support |
|-----------------|----------|--------------|------------|------------|--------------|
| Octokit         | Node.js  | Full         | Yes        | Yes        | Excellent    |
| node-github     | Node.js  | Full         | No         | No         | Limited      |
| Raw HTTP        | Node.js  | Full (manual)| N/A        | N/A        | N/A          |

**Recommendation:** Use Octokit for all GitHub API interactions in your Node.js project. It’s the official, most robust, and best-supported option for your use case[1][2].


---

*Generated by Task Master Research Command*  
*Timestamp: 2025-06-14T21:20:00.561Z*

```

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

```typescript
/**
 * @fileoverview NextCommand using Commander's native class pattern
 * Extends Commander.Command for better integration with the framework
 */

import path from 'node:path';
import { type Task, type TmCore, createTmCore } from '@tm/core';
import type { StorageType } from '@tm/core';
import boxen from 'boxen';
import chalk from 'chalk';
import { Command } from 'commander';
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
import { displayCommandHeader } from '../utils/display-helpers.js';
import { displayError } from '../utils/error-handler.js';
import { getProjectRoot } from '../utils/project-root.js';

/**
 * Options interface for the next command
 */
export interface NextCommandOptions {
	tag?: string;
	format?: 'text' | 'json';
	silent?: boolean;
	project?: string;
}

/**
 * Result type from next command
 */
export interface NextTaskResult {
	task: Task | null;
	found: boolean;
	tag: string;
	storageType: Exclude<StorageType, 'auto'>;
}

/**
 * NextCommand extending Commander's Command class
 * This is a thin presentation layer over @tm/core
 */
export class NextCommand extends Command {
	private tmCore?: TmCore;
	private lastResult?: NextTaskResult;

	constructor(name?: string) {
		super(name || 'next');

		// Configure the command
		this.description('Find the next available task to work on')
			.option('-t, --tag <tag>', 'Filter by tag')
			.option('-f, --format <format>', 'Output format (text, json)', 'text')
			.option('--silent', 'Suppress output (useful for programmatic usage)')
			.option(
				'-p, --project <path>',
				'Project root directory (auto-detected if not provided)'
			)
			.action(async (options: NextCommandOptions) => {
				await this.executeCommand(options);
			});
	}

	/**
	 * Execute the next command
	 */
	private async executeCommand(options: NextCommandOptions): Promise<void> {
		let hasError = false;
		try {
			// Validate options (throws on invalid options)
			this.validateOptions(options);

			// Initialize tm-core
			await this.initializeCore(getProjectRoot(options.project));

			// Get next task from core
			const result = await this.getNextTask(options);

			// Store result for programmatic access
			this.setLastResult(result);

			// Display results
			if (!options.silent) {
				this.displayResults(result, options);
			}
		} catch (error: any) {
			hasError = true;
			displayError(error, { skipExit: true });
		} finally {
			// Always clean up resources, even on error
			await this.cleanup();
		}

		// Exit after cleanup completes
		if (hasError) {
			process.exit(1);
		}
	}

	/**
	 * Validate command options
	 */
	private validateOptions(options: NextCommandOptions): void {
		// Validate format
		if (options.format && !['text', 'json'].includes(options.format)) {
			throw new Error(
				`Invalid format: ${options.format}. Valid formats are: text, json`
			);
		}
	}

	/**
	 * Initialize TmCore
	 */
	private async initializeCore(projectRoot: string): Promise<void> {
		if (!this.tmCore) {
			const resolved = path.resolve(projectRoot);
			this.tmCore = await createTmCore({ projectPath: resolved });
		}
	}

	/**
	 * Get next task from tm-core
	 */
	private async getNextTask(
		options: NextCommandOptions
	): Promise<NextTaskResult> {
		if (!this.tmCore) {
			throw new Error('TmCore not initialized');
		}

		// Call tm-core to get next task
		const task = await this.tmCore.tasks.getNext(options.tag);

		// Get storage type and active tag
		const storageType = this.tmCore.tasks.getStorageType();

		const activeTag = options.tag || this.tmCore.config.getActiveTag();

		return {
			task,
			found: task !== null,
			tag: activeTag,
			storageType
		};
	}

	/**
	 * Display results based on format
	 */
	private displayResults(
		result: NextTaskResult,
		options: NextCommandOptions
	): void {
		const format = options.format || 'text';

		switch (format) {
			case 'json':
				this.displayJson(result);
				break;

			case 'text':
			default:
				this.displayText(result);
				break;
		}
	}

	/**
	 * Display in JSON format
	 */
	private displayJson(result: NextTaskResult): void {
		console.log(JSON.stringify(result, null, 2));
	}

	/**
	 * Display in text format
	 */
	private displayText(result: NextTaskResult): void {
		// Display header with storage info
		displayCommandHeader(this.tmCore, {
			tag: result.tag || 'master',
			storageType: result.storageType
		});

		if (!result.found || !result.task) {
			// No next task available
			console.log(
				boxen(
					chalk.yellow(
						'No tasks available to work on. All tasks are either completed, blocked by dependencies, or in progress.'
					),
					{
						padding: 1,
						borderStyle: 'round',
						borderColor: 'yellow',
						title: '⚠️ NO TASKS AVAILABLE ⚠️',
						titleAlignment: 'center'
					}
				)
			);
			console.log(
				`\n${chalk.dim('Tip: Try')} ${chalk.cyan('task-master list --status pending')} ${chalk.dim('to see all pending tasks')}`
			);
			return;
		}

		const task = result.task;

		// Display the task details using the same component as 'show' command
		// with a custom header indicating this is the next task
		const customHeader = `Next Task: #${task.id} - ${task.title}`;
		displayTaskDetails(task, {
			customHeader,
			headerColor: 'green',
			showSuggestedActions: true,
			storageType: result.storageType
		});
	}

	/**
	 * Set the last result for programmatic access
	 */
	private setLastResult(result: NextTaskResult): void {
		this.lastResult = result;
	}

	/**
	 * Get the last result (for programmatic usage)
	 */
	getLastResult(): NextTaskResult | undefined {
		return this.lastResult;
	}

	/**
	 * Clean up resources
	 */
	async cleanup(): Promise<void> {
		if (this.tmCore) {
			this.tmCore = undefined;
		}
	}

	/**
	 * Register this command on an existing program
	 */
	static register(program: Command, name?: string): NextCommand {
		const nextCommand = new NextCommand(name);
		program.addCommand(nextCommand);
		return nextCommand;
	}
}

```

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

```javascript
import { jest } from '@jest/globals';

// Provide fs mock early so existsSync can be stubbed
jest.unstable_mockModule('fs', () => {
	const mockFs = {
		existsSync: jest.fn(() => true),
		writeFileSync: jest.fn(),
		readFileSync: jest.fn(),
		unlinkSync: jest.fn()
	};
	return { default: mockFs, ...mockFs };
});

// --- Mock dependencies ---
jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
	readJSON: jest.fn(),
	writeJSON: jest.fn(),
	log: jest.fn(),
	isSilentMode: jest.fn(() => false),
	findProjectRoot: jest.fn(() => '/project'),
	flattenTasksWithSubtasks: jest.fn(() => []),
	truncate: jest.fn((t) => t),
	isEmpty: jest.fn(() => false),
	resolveEnvVariable: jest.fn(),
	findTaskById: jest.fn(),
	getCurrentTag: jest.fn(() => 'master'),
	resolveTag: jest.fn(() => 'master'),
	addComplexityToTask: jest.fn((task, complexity) => ({ ...task, complexity })),
	getTasksForTag: jest.fn((data, tag) => data[tag]?.tasks || []),
	setTasksForTag: jest.fn(),
	ensureTagMetadata: jest.fn((tagObj) => tagObj)
}));

jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
	displayBanner: jest.fn(),
	getStatusWithColor: jest.fn((s) => s),
	startLoadingIndicator: jest.fn(() => ({ stop: jest.fn() })),
	stopLoadingIndicator: jest.fn(),
	succeedLoadingIndicator: jest.fn(),
	failLoadingIndicator: jest.fn(),
	warnLoadingIndicator: jest.fn(),
	infoLoadingIndicator: jest.fn(),
	displayAiUsageSummary: jest.fn(),
	displayContextAnalysis: jest.fn()
}));

jest.unstable_mockModule(
	'../../../../../scripts/modules/task-manager/generate-task-files.js',
	() => ({
		default: jest.fn().mockResolvedValue()
	})
);

jest.unstable_mockModule(
	'../../../../../scripts/modules/ai-services-unified.js',
	() => ({
		generateTextService: jest
			.fn()
			.mockResolvedValue({ mainResult: { content: '' }, telemetryData: {} })
	})
);

jest.unstable_mockModule(
	'../../../../../scripts/modules/config-manager.js',
	() => ({
		getDebugFlag: jest.fn(() => false),
		hasCodebaseAnalysis: jest.fn(() => false)
	})
);

jest.unstable_mockModule(
	'../../../../../scripts/modules/prompt-manager.js',
	() => ({
		default: jest.fn().mockReturnValue({
			loadPrompt: jest.fn().mockReturnValue('Update the subtask')
		}),
		getPromptManager: jest.fn().mockReturnValue({
			loadPrompt: jest.fn().mockReturnValue('Update the subtask')
		})
	})
);

jest.unstable_mockModule(
	'../../../../../scripts/modules/utils/contextGatherer.js',
	() => ({
		ContextGatherer: jest.fn().mockImplementation(() => ({
			gather: jest.fn().mockReturnValue({
				fullContext: '',
				summary: ''
			})
		}))
	})
);

// Mock @tm/bridge module
jest.unstable_mockModule('@tm/bridge', () => ({
	tryUpdateViaRemote: jest.fn().mockResolvedValue(null)
}));

// Mock bridge-utils module
jest.unstable_mockModule(
	'../../../../../scripts/modules/bridge-utils.js',
	() => ({
		createBridgeLogger: jest.fn(() => ({
			logger: {
				info: jest.fn(),
				warn: jest.fn(),
				error: jest.fn(),
				debug: jest.fn()
			},
			report: jest.fn(),
			isMCP: false
		}))
	})
);

// Mock fuzzyTaskSearch module
jest.unstable_mockModule(
	'../../../../../scripts/modules/utils/fuzzyTaskSearch.js',
	() => ({
		FuzzyTaskSearch: jest.fn().mockImplementation(() => ({
			search: jest.fn().mockReturnValue([])
		}))
	})
);

// Import mocked utils to leverage mocks later
const { readJSON, log } = await import(
	'../../../../../scripts/modules/utils.js'
);

// Import function under test
const { default: updateSubtaskById } = await import(
	'../../../../../scripts/modules/task-manager/update-subtask-by-id.js'
);

describe('updateSubtaskById validation', () => {
	beforeEach(() => {
		jest.clearAllMocks();
		jest.spyOn(process, 'exit').mockImplementation(() => {
			throw new Error('process.exit called');
		});
	});

	test('throws error on invalid subtask id format', async () => {
		await expect(
			updateSubtaskById(
				'tasks/tasks.json',
				'invalid',
				'my prompt',
				false,
				{
					tag: 'master'
				},
				'json'
			)
		).rejects.toThrow('Invalid subtask ID format');
	});

	test('throws error when prompt is empty', async () => {
		await expect(
			updateSubtaskById(
				'tasks/tasks.json',
				'1.1',
				'',
				false,
				{ tag: 'master' },
				'json'
			)
		).rejects.toThrow('Prompt cannot be empty');
	});

	test('throws error if tasks file does not exist', async () => {
		// Mock fs.existsSync to return false via jest.spyOn (dynamic import of fs)
		const fs = await import('fs');
		fs.existsSync.mockReturnValue(false);
		await expect(
			updateSubtaskById(
				'tasks/tasks.json',
				'1.1',
				'prompt',
				false,
				{
					tag: 'master'
				},
				'json'
			)
		).rejects.toThrow('Tasks file not found');
	});

	test('throws error if parent task missing', async () => {
		// Mock existsSync true
		const fs = await import('fs');
		fs.existsSync.mockReturnValue(true);
		// readJSON returns tasks without parent id 1
		readJSON.mockReturnValue({ tag: 'master', tasks: [] });
		await expect(
			updateSubtaskById(
				'tasks/tasks.json',
				'1.1',
				'prompt',
				false,
				{
					tag: 'master'
				},
				'json'
			)
		).rejects.toThrow('Parent task with ID 1 not found');
		// log called with error level
		expect(log).toHaveBeenCalled();
	});

	test('successfully updates subtask with valid inputs', async () => {
		const fs = await import('fs');
		const { writeJSON } = await import(
			'../../../../../scripts/modules/utils.js'
		);

		fs.existsSync.mockReturnValue(true);
		readJSON.mockReturnValue({
			tag: 'master',
			tasks: [
				{
					id: 1,
					title: 'Parent Task',
					subtasks: [{ id: 1, title: 'Original subtask', status: 'pending' }]
				}
			]
		});

		// updateSubtaskById doesn't return a value on success, it just executes
		await expect(
			updateSubtaskById(
				'tasks/tasks.json',
				'1.1',
				'Update this subtask',
				false,
				{ tag: 'master' },
				'json'
			)
		).resolves.not.toThrow();

		expect(writeJSON).toHaveBeenCalled();
	});
});

```

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

```typescript
/**
 * Hook for handling VS Code messages
 */

import { useEffect, useCallback, useRef } from 'react';
import type { AppState, AppAction } from '../types';
import { createToast } from '../utils/toast';
import { REQUEST_TIMEOUT } from '../constants';

interface PendingRequest {
	resolve: Function;
	reject: Function;
	timeout: NodeJS.Timeout;
}

let requestCounter = 0;

export const useVSCodeMessages = (
	vscode: ReturnType<NonNullable<typeof window.acquireVsCodeApi>> | undefined,
	state: AppState,
	dispatch: React.Dispatch<AppAction>
) => {
	const pendingRequestsRef = useRef(new Map<string, PendingRequest>());

	const sendMessage = useCallback(
		(message: any): Promise<any> => {
			if (!vscode) {
				return Promise.reject(new Error('VS Code API not available'));
			}

			return new Promise((resolve, reject) => {
				const requestId = `req_${++requestCounter}_${Date.now()}`;

				const timeout = setTimeout(() => {
					pendingRequestsRef.current.delete(requestId);
					reject(new Error('Request timeout'));
				}, REQUEST_TIMEOUT);

				pendingRequestsRef.current.set(requestId, { resolve, reject, timeout });

				vscode.postMessage({
					...message,
					requestId
				});
			});
		},
		[vscode]
	);

	useEffect(() => {
		if (!vscode) return;

		const handleMessage = (event: MessageEvent) => {
			const message = event.data;
			console.log('📥 Received message:', message.type, message);

			// Handle request/response pattern
			if (message.requestId) {
				const pending = pendingRequestsRef.current.get(message.requestId);
				if (pending) {
					clearTimeout(pending.timeout);
					pendingRequestsRef.current.delete(message.requestId);

					if (message.type === 'response') {
						// Check for explicit success field, default to true if data exists
						const isSuccess =
							message.success !== undefined
								? message.success
								: message.data !== undefined;
						if (isSuccess) {
							pending.resolve(message.data);
						} else {
							pending.reject(new Error(message.error || 'Request failed'));
						}
					} else if (message.type === 'error') {
						pending.reject(new Error(message.error || 'Request failed'));
					}
				}
				return;
			}

			// Handle other message types
			switch (message.type) {
				case 'connectionStatus':
					dispatch({
						type: 'SET_CONNECTION_STATUS',
						payload: {
							isConnected: message.data?.isConnected || false,
							status: message.data?.status || 'Unknown'
						}
					});
					break;

				case 'tasksData':
					console.log('📋 Received tasks data:', message.data);
					dispatch({ type: 'SET_TASKS', payload: message.data });
					break;

				case 'pollingStatus':
					dispatch({
						type: 'SET_POLLING_STATUS',
						payload: {
							isActive: message.isActive,
							errorCount: message.errorCount || 0
						}
					});
					break;

				case 'pollingUpdate':
					console.log('🔄 Polling update received:', {
						tasksCount: message.data?.length,
						userInteracting: state.polling.isUserInteracting,
						offlineMode: state.polling.isOfflineMode
					});

					if (
						!state.polling.isUserInteracting &&
						!state.polling.isOfflineMode
					) {
						dispatch({
							type: 'TASKS_UPDATED_FROM_POLLING',
							payload: message.data
						});
					}
					break;

				case 'networkStatus':
					dispatch({
						type: 'SET_NETWORK_STATUS',
						payload: message.data
					});
					break;

				case 'cachedTasks':
					console.log('📦 Received cached tasks:', message.data);
					dispatch({
						type: 'LOAD_CACHED_TASKS',
						payload: message.data
					});
					break;

				case 'errorNotification':
					handleErrorNotification(message, dispatch);
					break;

				case 'error':
					handleGeneralError(message, dispatch);
					break;

				case 'reactError':
					console.log('🔥 React error reported to extension:', message);
					dispatch({
						type: 'ADD_TOAST',
						payload: createToast(
							'error',
							'UI Error',
							'A component error occurred. The extension may need to be reloaded.',
							10000
						)
					});
					break;

				default:
					console.log('❓ Unknown message type:', message.type);
			}
		};

		window.addEventListener('message', handleMessage);
		return () => window.removeEventListener('message', handleMessage);
	}, [vscode, state.polling, dispatch]);

	return { sendMessage };
};

function handleErrorNotification(
	message: any,
	dispatch: React.Dispatch<AppAction>
) {
	console.log('📨 Error notification received:', message);
	const errorData = message.data;

	// Map severity to toast type
	let toastType: 'error' | 'warning' | 'info' = 'error';
	if (errorData.severity === 'high' || errorData.severity === 'critical') {
		toastType = 'error';
	} else if (errorData.severity === 'medium') {
		toastType = 'warning';
	} else {
		toastType = 'info';
	}

	// Create appropriate toast based on error category
	const title =
		errorData.category === 'network'
			? 'Network Error'
			: errorData.category === 'mcp_connection'
				? 'Connection Error'
				: errorData.category === 'task_loading'
					? 'Task Loading Error'
					: errorData.category === 'ui_rendering'
						? 'UI Error'
						: 'Error';

	dispatch({
		type: 'ADD_TOAST',
		payload: createToast(
			toastType,
			title,
			errorData.message,
			errorData.duration || (toastType === 'error' ? 8000 : 5000)
		)
	});
}

function handleGeneralError(message: any, dispatch: React.Dispatch<AppAction>) {
	console.log('❌ General error from extension:', message);
	const errorTitle =
		message.errorType === 'connection' ? 'Connection Error' : 'Error';
	const errorMessage = message.error || 'An unknown error occurred';

	dispatch({
		type: 'SET_ERROR',
		payload: errorMessage
	});

	dispatch({
		type: 'ADD_TOAST',
		payload: createToast('error', errorTitle, errorMessage, 8000)
	});

	// Set offline mode for connection errors
	if (message.errorType === 'connection') {
		dispatch({
			type: 'SET_NETWORK_STATUS',
			payload: {
				isOfflineMode: true,
				connectionStatus: 'offline',
				reconnectAttempts: 0
			}
		});
	}
}

```

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

```typescript
/**
 * @fileoverview TmCore - Unified facade for all Task Master functionality
 * This is the ONLY entry point for using tm-core
 */

import path from 'node:path';
import { AuthDomain } from './modules/auth/auth-domain.js';
import { ConfigDomain } from './modules/config/config-domain.js';
import { ConfigManager } from './modules/config/managers/config-manager.js';
import { GitDomain } from './modules/git/git-domain.js';
import { IntegrationDomain } from './modules/integration/integration-domain.js';
import { TasksDomain } from './modules/tasks/tasks-domain.js';
import { WorkflowDomain } from './modules/workflow/workflow-domain.js';

import {
	ERROR_CODES,
	TaskMasterError
} from './common/errors/task-master-error.js';
import type { IConfiguration } from './common/interfaces/configuration.interface.js';
import {
	type Logger,
	type LoggerConfig,
	createLogger
} from './common/logger/index.js';

/**
 * Options for creating TmCore instance
 */
export interface TmCoreOptions {
	/** Absolute path to project root */
	projectPath: string;
	/** Optional configuration overrides */
	configuration?: Partial<IConfiguration>;
	/** Optional logger configuration for MCP integration and debugging */
	loggerConfig?: LoggerConfig;
}

/**
 * TmCore - Unified facade providing access to all Task Master domains
 *
 * @example Basic usage
 * ```typescript
 * const tmcore = await createTmCore({ projectPath: process.cwd() });
 *
 * // Access any domain
 * await tmcore.auth.authenticateWithOAuth();
 * const tasks = await tmcore.tasks.list();
 * await tmcore.workflow.start({ taskId: '1' });
 * await tmcore.git.commit('feat: add feature');
 * const modelConfig = tmcore.config.getModelConfig();
 * await tmcore.integration.exportTasks({ ... });
 * ```
 *
 * @example MCP integration with logging
 * ```typescript
 * import { LogLevel } from '@tm/core/logger';
 *
 * // In MCP tool execute function
 * async function execute(args, log) {
 *   const tmcore = await createTmCore({
 *     projectPath: args.projectRoot,
 *     loggerConfig: {
 *       level: LogLevel.INFO,
 *       mcpMode: true,
 *       logCallback: log  // MCP log function
 *     }
 *   });
 *
 *   // All internal logging will now be sent to MCP
 *   const tasks = await tmcore.tasks.list();
 *
 *   // You can also log custom messages
 *   tmcore.logger.info('Operation completed');
 * }
 * ```
 */
export class TmCore {
	// Core infrastructure
	private readonly _projectPath: string;
	private _configManager!: ConfigManager;
	private _logger!: Logger;

	// Private writable properties
	private _tasks!: TasksDomain;
	private _auth!: AuthDomain;
	private _workflow!: WorkflowDomain;
	private _git!: GitDomain;
	private _config!: ConfigDomain;
	private _integration!: IntegrationDomain;

	// Public readonly getters
	get tasks(): TasksDomain {
		return this._tasks;
	}
	get auth(): AuthDomain {
		return this._auth;
	}
	get workflow(): WorkflowDomain {
		return this._workflow;
	}
	get git(): GitDomain {
		return this._git;
	}
	get config(): ConfigDomain {
		return this._config;
	}
	get integration(): IntegrationDomain {
		return this._integration;
	}
	get logger(): Logger {
		return this._logger;
	}

	/**
	 * Create and initialize a new TmCore instance
	 * This is the ONLY way to create TmCore
	 *
	 * @param options - Configuration options
	 * @returns Fully initialized TmCore instance
	 */
	static async create(options: TmCoreOptions): Promise<TmCore> {
		const instance = new TmCore(options);
		await instance.initialize();
		return instance;
	}

	private _options: TmCoreOptions;

	/**
	 * Private constructor - use TmCore.create() instead
	 * This ensures TmCore is always properly initialized
	 */
	private constructor(options: TmCoreOptions) {
		if (!options.projectPath) {
			throw new TaskMasterError(
				'Project path is required',
				ERROR_CODES.MISSING_CONFIGURATION
			);
		}

		// Validate that projectPath is absolute
		if (!path.isAbsolute(options.projectPath)) {
			throw new TaskMasterError(
				`Project path must be an absolute path, received: "${options.projectPath}"`,
				ERROR_CODES.INVALID_INPUT
			);
		}

		// Normalize the path
		this._projectPath = path.resolve(options.projectPath);
		this._options = options;
		// Domain facades will be initialized in initialize()
	}

	/**
	 * Initialize the TmCore instance
	 * Private - only called by the factory method
	 */
	private async initialize(): Promise<void> {
		try {
			// Initialize logger first (before anything else that might log)
			this._logger = createLogger(this._options.loggerConfig);

			// Create config manager
			this._configManager = await ConfigManager.create(this._projectPath);

			// Apply configuration overrides if provided
			if (this._options.configuration) {
				await this._configManager.updateConfig(this._options.configuration);
			}

			// Initialize domain facades
			this._auth = new AuthDomain();
			this._tasks = new TasksDomain(this._configManager, this._auth);
			this._workflow = new WorkflowDomain(this._configManager);
			this._git = new GitDomain(this._projectPath);
			this._config = new ConfigDomain(this._configManager);
			this._integration = new IntegrationDomain(this._configManager);

			// Initialize domains that need async setup
			await this._tasks.initialize();

			// Log successful initialization
			this._logger.info('TmCore initialized successfully');
		} catch (error) {
			// Log error if logger is available
			if (this._logger) {
				this._logger.error('Failed to initialize TmCore:', error);
			}

			throw new TaskMasterError(
				'Failed to initialize TmCore',
				ERROR_CODES.INTERNAL_ERROR,
				{ operation: 'initialize' },
				error as Error
			);
		}
	}

	/**
	 * Get project root path
	 */
	get projectPath(): string {
		return this._projectPath;
	}
}

/**
 * Factory function to create a new TmCore instance
 * This is the recommended way to create TmCore
 *
 * @param options - Configuration options
 * @returns Fully initialized TmCore instance
 */
export async function createTmCore(options: TmCoreOptions): Promise<TmCore> {
	return TmCore.create(options);
}

```
Page 13/50FirstPrevNextLast