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

# Directory Structure

```
├── .changeset
│   ├── config.json
│   └── README.md
├── .claude
│   ├── agents
│   │   ├── task-checker.md
│   │   ├── task-executor.md
│   │   └── task-orchestrator.md
│   ├── commands
│   │   ├── dedupe.md
│   │   └── tm
│   │       ├── add-dependency
│   │       │   └── add-dependency.md
│   │       ├── add-subtask
│   │       │   ├── add-subtask.md
│   │       │   └── convert-task-to-subtask.md
│   │       ├── add-task
│   │       │   └── add-task.md
│   │       ├── analyze-complexity
│   │       │   └── analyze-complexity.md
│   │       ├── complexity-report
│   │       │   └── complexity-report.md
│   │       ├── expand
│   │       │   ├── expand-all-tasks.md
│   │       │   └── expand-task.md
│   │       ├── fix-dependencies
│   │       │   └── fix-dependencies.md
│   │       ├── generate
│   │       │   └── generate-tasks.md
│   │       ├── help.md
│   │       ├── init
│   │       │   ├── init-project-quick.md
│   │       │   └── init-project.md
│   │       ├── learn.md
│   │       ├── list
│   │       │   ├── list-tasks-by-status.md
│   │       │   ├── list-tasks-with-subtasks.md
│   │       │   └── list-tasks.md
│   │       ├── models
│   │       │   ├── setup-models.md
│   │       │   └── view-models.md
│   │       ├── next
│   │       │   └── next-task.md
│   │       ├── parse-prd
│   │       │   ├── parse-prd-with-research.md
│   │       │   └── parse-prd.md
│   │       ├── remove-dependency
│   │       │   └── remove-dependency.md
│   │       ├── remove-subtask
│   │       │   └── remove-subtask.md
│   │       ├── remove-subtasks
│   │       │   ├── remove-all-subtasks.md
│   │       │   └── remove-subtasks.md
│   │       ├── remove-task
│   │       │   └── remove-task.md
│   │       ├── set-status
│   │       │   ├── to-cancelled.md
│   │       │   ├── to-deferred.md
│   │       │   ├── to-done.md
│   │       │   ├── to-in-progress.md
│   │       │   ├── to-pending.md
│   │       │   └── to-review.md
│   │       ├── setup
│   │       │   ├── install-taskmaster.md
│   │       │   └── quick-install-taskmaster.md
│   │       ├── show
│   │       │   └── show-task.md
│   │       ├── status
│   │       │   └── project-status.md
│   │       ├── sync-readme
│   │       │   └── sync-readme.md
│   │       ├── tm-main.md
│   │       ├── update
│   │       │   ├── update-single-task.md
│   │       │   ├── update-task.md
│   │       │   └── update-tasks-from-id.md
│   │       ├── utils
│   │       │   └── analyze-project.md
│   │       ├── validate-dependencies
│   │       │   └── validate-dependencies.md
│   │       └── workflows
│   │           ├── auto-implement-tasks.md
│   │           ├── command-pipeline.md
│   │           └── smart-workflow.md
│   └── TM_COMMANDS_GUIDE.md
├── .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
│   └── 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
│   │   ├── 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
│   │   ├── test-prd.txt
│   │   └── tm-core-phase-1.txt
│   ├── reports
│   │   ├── task-complexity-report_cc-kiro-hooks.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.txt
├── .vscode
│   ├── extensions.json
│   └── settings.json
├── apps
│   ├── cli
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── commands
│   │   │   │   ├── auth.command.ts
│   │   │   │   ├── context.command.ts
│   │   │   │   ├── list.command.ts
│   │   │   │   ├── set-status.command.ts
│   │   │   │   ├── show.command.ts
│   │   │   │   └── start.command.ts
│   │   │   ├── index.ts
│   │   │   ├── ui
│   │   │   │   ├── components
│   │   │   │   │   ├── dashboard.component.ts
│   │   │   │   │   ├── header.component.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── next-task.component.ts
│   │   │   │   │   ├── suggested-steps.component.ts
│   │   │   │   │   └── task-detail.component.ts
│   │   │   │   └── index.ts
│   │   │   └── utils
│   │   │       ├── auto-update.ts
│   │   │       └── ui.ts
│   │   └── tsconfig.json
│   ├── 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
│   │   │   └── task-structure.mdx
│   │   ├── CHANGELOG.md
│   │   ├── docs.json
│   │   ├── favicon.svg
│   │   ├── getting-started
│   │   │   ├── 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
│   │   ├── 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
├── assets
│   ├── .windsurfrules
│   ├── AGENTS.md
│   ├── claude
│   │   ├── agents
│   │   │   ├── task-checker.md
│   │   │   ├── task-executor.md
│   │   │   └── task-orchestrator.md
│   │   ├── commands
│   │   │   └── tm
│   │   │       ├── add-dependency
│   │   │       │   └── add-dependency.md
│   │   │       ├── add-subtask
│   │   │       │   ├── add-subtask.md
│   │   │       │   └── convert-task-to-subtask.md
│   │   │       ├── add-task
│   │   │       │   └── add-task.md
│   │   │       ├── analyze-complexity
│   │   │       │   └── analyze-complexity.md
│   │   │       ├── clear-subtasks
│   │   │       │   ├── clear-all-subtasks.md
│   │   │       │   └── clear-subtasks.md
│   │   │       ├── complexity-report
│   │   │       │   └── complexity-report.md
│   │   │       ├── expand
│   │   │       │   ├── expand-all-tasks.md
│   │   │       │   └── expand-task.md
│   │   │       ├── fix-dependencies
│   │   │       │   └── fix-dependencies.md
│   │   │       ├── generate
│   │   │       │   └── generate-tasks.md
│   │   │       ├── help.md
│   │   │       ├── init
│   │   │       │   ├── init-project-quick.md
│   │   │       │   └── init-project.md
│   │   │       ├── learn.md
│   │   │       ├── list
│   │   │       │   ├── list-tasks-by-status.md
│   │   │       │   ├── list-tasks-with-subtasks.md
│   │   │       │   └── list-tasks.md
│   │   │       ├── models
│   │   │       │   ├── setup-models.md
│   │   │       │   └── view-models.md
│   │   │       ├── next
│   │   │       │   └── next-task.md
│   │   │       ├── parse-prd
│   │   │       │   ├── parse-prd-with-research.md
│   │   │       │   └── parse-prd.md
│   │   │       ├── remove-dependency
│   │   │       │   └── remove-dependency.md
│   │   │       ├── remove-subtask
│   │   │       │   └── remove-subtask.md
│   │   │       ├── remove-subtasks
│   │   │       │   ├── remove-all-subtasks.md
│   │   │       │   └── remove-subtasks.md
│   │   │       ├── remove-task
│   │   │       │   └── remove-task.md
│   │   │       ├── set-status
│   │   │       │   ├── to-cancelled.md
│   │   │       │   ├── to-deferred.md
│   │   │       │   ├── to-done.md
│   │   │       │   ├── to-in-progress.md
│   │   │       │   ├── to-pending.md
│   │   │       │   └── to-review.md
│   │   │       ├── setup
│   │   │       │   ├── install-taskmaster.md
│   │   │       │   └── quick-install-taskmaster.md
│   │   │       ├── show
│   │   │       │   └── show-task.md
│   │   │       ├── status
│   │   │       │   └── project-status.md
│   │   │       ├── sync-readme
│   │   │       │   └── sync-readme.md
│   │   │       ├── tm-main.md
│   │   │       ├── update
│   │   │       │   ├── update-single-task.md
│   │   │       │   ├── update-task.md
│   │   │       │   └── update-tasks-from-id.md
│   │   │       ├── utils
│   │   │       │   └── analyze-project.md
│   │   │       ├── validate-dependencies
│   │   │       │   └── validate-dependencies.md
│   │   │       └── workflows
│   │   │           ├── auto-implement-tasks.md
│   │   │           ├── command-pipeline.md
│   │   │           └── smart-workflow.md
│   │   └── TM_COMMANDS_GUIDE.md
│   ├── config.json
│   ├── env.example
│   ├── example_prd.txt
│   ├── 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.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
│   ├── CLI-COMMANDER-PATTERN.md
│   ├── command-reference.md
│   ├── configuration.md
│   ├── contributor-docs
│   │   └── testing-roo-integration.md
│   ├── cross-tag-task-movement.md
│   ├── examples
│   │   └── claude-code-usage.md
│   ├── examples.md
│   ├── licensing.md
│   ├── mcp-provider-guide.md
│   ├── mcp-provider.md
│   ├── migration-guide.md
│   ├── models.md
│   ├── providers
│   │   └── gemini-cli.md
│   ├── README.md
│   ├── scripts
│   │   └── models-json-to-markdown.js
│   ├── task-structure.md
│   └── tutorial.md
├── images
│   └── 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
│       │   │   ├── list-tasks.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
│       │   │   ├── show-task.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
│           ├── get-task.js
│           ├── get-tasks.js
│           ├── index.js
│           ├── initialize-project.js
│           ├── list-tags.js
│           ├── models.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.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
│   ├── build-config
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── src
│   │   │   └── tsdown.base.ts
│   │   └── tsconfig.json
│   └── tm-core
│       ├── .gitignore
│       ├── CHANGELOG.md
│       ├── docs
│       │   └── listTasks-architecture.md
│       ├── package.json
│       ├── POC-STATUS.md
│       ├── README.md
│       ├── src
│       │   ├── auth
│       │   │   ├── auth-manager.test.ts
│       │   │   ├── auth-manager.ts
│       │   │   ├── config.ts
│       │   │   ├── credential-store.test.ts
│       │   │   ├── credential-store.ts
│       │   │   ├── index.ts
│       │   │   ├── oauth-service.ts
│       │   │   ├── supabase-session-storage.ts
│       │   │   └── types.ts
│       │   ├── clients
│       │   │   ├── index.ts
│       │   │   └── supabase-client.ts
│       │   ├── config
│       │   │   ├── config-manager.spec.ts
│       │   │   ├── config-manager.ts
│       │   │   ├── index.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
│       │   ├── constants
│       │   │   └── index.ts
│       │   ├── entities
│       │   │   └── task.entity.ts
│       │   ├── errors
│       │   │   ├── index.ts
│       │   │   └── task-master-error.ts
│       │   ├── executors
│       │   │   ├── base-executor.ts
│       │   │   ├── claude-executor.ts
│       │   │   ├── executor-factory.ts
│       │   │   ├── executor-service.ts
│       │   │   ├── index.ts
│       │   │   └── types.ts
│       │   ├── index.ts
│       │   ├── interfaces
│       │   │   ├── ai-provider.interface.ts
│       │   │   ├── configuration.interface.ts
│       │   │   ├── index.ts
│       │   │   └── storage.interface.ts
│       │   ├── logger
│       │   │   ├── factory.ts
│       │   │   ├── index.ts
│       │   │   └── logger.ts
│       │   ├── mappers
│       │   │   └── TaskMapper.ts
│       │   ├── parser
│       │   │   └── index.ts
│       │   ├── providers
│       │   │   ├── ai
│       │   │   │   ├── base-provider.ts
│       │   │   │   └── index.ts
│       │   │   └── index.ts
│       │   ├── repositories
│       │   │   ├── supabase-task-repository.ts
│       │   │   └── task-repository.interface.ts
│       │   ├── services
│       │   │   ├── index.ts
│       │   │   ├── organization.service.ts
│       │   │   ├── task-execution-service.ts
│       │   │   └── task-service.ts
│       │   ├── storage
│       │   │   ├── api-storage.ts
│       │   │   ├── file-storage
│       │   │   │   ├── file-operations.ts
│       │   │   │   ├── file-storage.ts
│       │   │   │   ├── format-handler.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── path-resolver.ts
│       │   │   ├── index.ts
│       │   │   └── storage-factory.ts
│       │   ├── subpath-exports.test.ts
│       │   ├── task-master-core.ts
│       │   ├── types
│       │   │   ├── database.types.ts
│       │   │   ├── index.ts
│       │   │   └── legacy.ts
│       │   └── utils
│       │       ├── id-generator.ts
│       │       └── index.ts
│       ├── tests
│       │   ├── integration
│       │   │   └── list-tasks.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
│   ├── dev.js
│   ├── init.js
│   ├── modules
│   │   ├── ai-services-unified.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
├── src
│   ├── ai-providers
│   │   ├── anthropic.js
│   │   ├── azure.js
│   │   ├── base-provider.js
│   │   ├── bedrock.js
│   │   ├── claude-code.js
│   │   ├── custom-sdk
│   │   │   ├── claude-code
│   │   │   │   ├── errors.js
│   │   │   │   ├── index.js
│   │   │   │   ├── json-extractor.js
│   │   │   │   ├── language-model.js
│   │   │   │   ├── message-converter.js
│   │   │   │   └── types.js
│   │   │   └── grok-cli
│   │   │       ├── errors.js
│   │   │       ├── index.js
│   │   │       ├── json-extractor.js
│   │   │       ├── language-model.js
│   │   │       ├── message-converter.js
│   │   │       └── types.js
│   │   ├── gemini-cli.js
│   │   ├── google-vertex.js
│   │   ├── google.js
│   │   ├── grok-cli.js
│   │   ├── groq.js
│   │   ├── index.js
│   │   ├── ollama.js
│   │   ├── openai.js
│   │   ├── openrouter.js
│   │   ├── perplexity.js
│   │   └── xai.js
│   ├── constants
│   │   ├── commands.js
│   │   ├── paths.js
│   │   ├── profiles.js
│   │   ├── providers.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
│   ├── 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
│   ├── fixture
│   │   └── test-tasks.json
│   ├── fixtures
│   │   ├── .taskmasterconfig
│   │   ├── sample-claude-response.js
│   │   ├── sample-prd.txt
│   │   └── sample-tasks.js
│   ├── integration
│   │   ├── 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
│   ├── 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
│       │   ├── claude-code.test.js
│       │   ├── custom-sdk
│       │   │   └── claude-code
│       │   │       └── language-model.test.js
│       │   ├── gemini-cli.test.js
│       │   ├── mcp-components.test.js
│       │   └── openai.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
│       ├── 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
│       ├── providers
│       │   └── provider-registry.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
│       │       │   ├── move-task-cross-tag.test.js
│       │       │   ├── move-task.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
```

# Files

--------------------------------------------------------------------------------
/scripts/modules/task-manager/set-task-status.js:
--------------------------------------------------------------------------------

```javascript
  1 | import path from 'path';
  2 | import chalk from 'chalk';
  3 | import boxen from 'boxen';
  4 | 
  5 | import {
  6 | 	log,
  7 | 	readJSON,
  8 | 	writeJSON,
  9 | 	findTaskById,
 10 | 	ensureTagMetadata
 11 | } from '../utils.js';
 12 | import { displayBanner } from '../ui.js';
 13 | import { validateTaskDependencies } from '../dependency-manager.js';
 14 | import { getDebugFlag } from '../config-manager.js';
 15 | import updateSingleTaskStatus from './update-single-task-status.js';
 16 | import generateTaskFiles from './generate-task-files.js';
 17 | import {
 18 | 	isValidTaskStatus,
 19 | 	TASK_STATUS_OPTIONS
 20 | } from '../../../src/constants/task-status.js';
 21 | 
 22 | /**
 23 |  * Set the status of a task
 24 |  * @param {string} tasksPath - Path to the tasks.json file
 25 |  * @param {string} taskIdInput - Task ID(s) to update
 26 |  * @param {string} newStatus - New status
 27 |  * @param {Object} options - Additional options (mcpLog for MCP mode, projectRoot for tag resolution)
 28 |  * @param {string} [options.projectRoot] - Project root path
 29 |  * @param {string} [options.tag] - Optional tag to override current tag resolution
 30 |  * @param {string} [options.mcpLog] - MCP logger object
 31 |  * @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
 32 |  */
 33 | async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
 34 | 	const { projectRoot, tag } = options;
 35 | 	try {
 36 | 		if (!isValidTaskStatus(newStatus)) {
 37 | 			throw new Error(
 38 | 				`Error: Invalid status value: ${newStatus}. Use one of: ${TASK_STATUS_OPTIONS.join(', ')}`
 39 | 			);
 40 | 		}
 41 | 		// Determine if we're in MCP mode by checking for mcpLog
 42 | 		const isMcpMode = !!options?.mcpLog;
 43 | 
 44 | 		// Only display UI elements if not in MCP mode
 45 | 		if (!isMcpMode) {
 46 | 			console.log(
 47 | 				boxen(chalk.white.bold(`Updating Task Status to: ${newStatus}`), {
 48 | 					padding: 1,
 49 | 					borderColor: 'blue',
 50 | 					borderStyle: 'round'
 51 | 				})
 52 | 			);
 53 | 		}
 54 | 
 55 | 		log('info', `Reading tasks from ${tasksPath}...`);
 56 | 
 57 | 		// Read the raw data without tag resolution to preserve tagged structure
 58 | 		let rawData = readJSON(tasksPath, projectRoot, tag); // No tag parameter
 59 | 
 60 | 		// Handle the case where readJSON returns resolved data with _rawTaggedData
 61 | 		if (rawData && rawData._rawTaggedData) {
 62 | 			// Use the raw tagged data and discard the resolved view
 63 | 			rawData = rawData._rawTaggedData;
 64 | 		}
 65 | 
 66 | 		// Ensure the tag exists in the raw data
 67 | 		if (!rawData || !rawData[tag] || !Array.isArray(rawData[tag].tasks)) {
 68 | 			throw new Error(
 69 | 				`Invalid tasks file or tag "${tag}" not found at ${tasksPath}`
 70 | 			);
 71 | 		}
 72 | 
 73 | 		// Get the tasks for the current tag
 74 | 		const data = {
 75 | 			tasks: rawData[tag].tasks,
 76 | 			tag,
 77 | 			_rawTaggedData: rawData
 78 | 		};
 79 | 
 80 | 		if (!data || !data.tasks) {
 81 | 			throw new Error(`No valid tasks found in ${tasksPath}`);
 82 | 		}
 83 | 
 84 | 		// Handle multiple task IDs (comma-separated)
 85 | 		const taskIds = taskIdInput.split(',').map((id) => id.trim());
 86 | 		const updatedTasks = [];
 87 | 
 88 | 		// Update each task and capture old status for display
 89 | 		for (const id of taskIds) {
 90 | 			// Capture old status before updating
 91 | 			let oldStatus = 'unknown';
 92 | 
 93 | 			if (id.includes('.')) {
 94 | 				// Handle subtask
 95 | 				const [parentId, subtaskId] = id
 96 | 					.split('.')
 97 | 					.map((id) => parseInt(id, 10));
 98 | 				const parentTask = data.tasks.find((t) => t.id === parentId);
 99 | 				if (parentTask?.subtasks) {
100 | 					const subtask = parentTask.subtasks.find((st) => st.id === subtaskId);
101 | 					oldStatus = subtask?.status || 'pending';
102 | 				}
103 | 			} else {
104 | 				// Handle regular task
105 | 				const taskId = parseInt(id, 10);
106 | 				const task = data.tasks.find((t) => t.id === taskId);
107 | 				oldStatus = task?.status || 'pending';
108 | 			}
109 | 
110 | 			await updateSingleTaskStatus(tasksPath, id, newStatus, data, !isMcpMode);
111 | 			updatedTasks.push({ id, oldStatus, newStatus });
112 | 		}
113 | 
114 | 		// Update the raw data structure with the modified tasks
115 | 		rawData[tag].tasks = data.tasks;
116 | 
117 | 		// Ensure the tag has proper metadata
118 | 		ensureTagMetadata(rawData[tag], {
119 | 			description: `Tasks for ${tag} context`
120 | 		});
121 | 
122 | 		// Write the updated raw data back to the file
123 | 		// The writeJSON function will automatically filter out _rawTaggedData
124 | 		writeJSON(tasksPath, rawData, projectRoot, tag);
125 | 
126 | 		// Validate dependencies after status update
127 | 		log('info', 'Validating dependencies after status update...');
128 | 		validateTaskDependencies(data.tasks);
129 | 
130 | 		// Generate individual task files
131 | 		// log('info', 'Regenerating task files...');
132 | 		// await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
133 | 		// 	mcpLog: options.mcpLog
134 | 		// });
135 | 
136 | 		// Display success message - only in CLI mode
137 | 		if (!isMcpMode) {
138 | 			for (const updateInfo of updatedTasks) {
139 | 				const { id, oldStatus, newStatus: updatedStatus } = updateInfo;
140 | 
141 | 				console.log(
142 | 					boxen(
143 | 						chalk.white.bold(`Successfully updated task ${id} status:`) +
144 | 							'\n' +
145 | 							`From: ${chalk.yellow(oldStatus)}\n` +
146 | 							`To:   ${chalk.green(updatedStatus)}`,
147 | 						{ padding: 1, borderColor: 'green', borderStyle: 'round' }
148 | 					)
149 | 				);
150 | 			}
151 | 		}
152 | 
153 | 		// Return success value for programmatic use
154 | 		return {
155 | 			success: true,
156 | 			updatedTasks: updatedTasks.map(({ id, oldStatus, newStatus }) => ({
157 | 				id,
158 | 				oldStatus,
159 | 				newStatus
160 | 			}))
161 | 		};
162 | 	} catch (error) {
163 | 		log('error', `Error setting task status: ${error.message}`);
164 | 
165 | 		// Only show error UI in CLI mode
166 | 		if (!options?.mcpLog) {
167 | 			console.error(chalk.red(`Error: ${error.message}`));
168 | 
169 | 			// Pass session to getDebugFlag
170 | 			if (getDebugFlag(options?.session)) {
171 | 				// Use getter
172 | 				console.error(error);
173 | 			}
174 | 
175 | 			process.exit(1);
176 | 		} else {
177 | 			// In MCP mode, throw the error for the caller to handle
178 | 			throw error;
179 | 		}
180 | 	}
181 | }
182 | 
183 | export default setTaskStatus;
184 | 
```

--------------------------------------------------------------------------------
/tests/unit/scripts/modules/dependency-manager/fix-dependencies-command.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Unit test to ensure fixDependenciesCommand writes JSON with the correct
  3 |  * projectRoot and tag arguments so that tag data is preserved.
  4 |  */
  5 | 
  6 | import { jest } from '@jest/globals';
  7 | 
  8 | // Mock process.exit to prevent test termination
  9 | const mockProcessExit = jest.fn();
 10 | const originalExit = process.exit;
 11 | process.exit = mockProcessExit;
 12 | 
 13 | // Mock utils.js BEFORE importing the module under test
 14 | jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
 15 | 	readJSON: jest.fn(),
 16 | 	writeJSON: jest.fn(),
 17 | 	log: jest.fn(),
 18 | 	findProjectRoot: jest.fn(() => '/mock/project/root'),
 19 | 	getCurrentTag: jest.fn(() => 'master'),
 20 | 	taskExists: jest.fn(() => true),
 21 | 	formatTaskId: jest.fn((id) => id),
 22 | 	findCycles: jest.fn(() => []),
 23 | 	traverseDependencies: jest.fn((sourceTasks, allTasks, options = {}) => []),
 24 | 	isSilentMode: jest.fn(() => true),
 25 | 	resolveTag: jest.fn(() => 'master'),
 26 | 	getTasksForTag: jest.fn(() => []),
 27 | 	setTasksForTag: jest.fn(),
 28 | 	enableSilentMode: jest.fn(),
 29 | 	disableSilentMode: jest.fn(),
 30 | 	isEmpty: jest.fn((value) => {
 31 | 		if (value === null || value === undefined) return true;
 32 | 		if (Array.isArray(value)) return value.length === 0;
 33 | 		if (typeof value === 'object' && value !== null)
 34 | 			return Object.keys(value).length === 0;
 35 | 		return false; // Not an array or object
 36 | 	}),
 37 | 	resolveEnvVariable: jest.fn()
 38 | }));
 39 | 
 40 | // Mock ui.js
 41 | jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
 42 | 	displayBanner: jest.fn(),
 43 | 	formatDependenciesWithStatus: jest.fn()
 44 | }));
 45 | 
 46 | // Mock task-manager.js
 47 | jest.unstable_mockModule(
 48 | 	'../../../../../scripts/modules/task-manager.js',
 49 | 	() => ({
 50 | 		generateTaskFiles: jest.fn()
 51 | 	})
 52 | );
 53 | 
 54 | // Mock external libraries
 55 | jest.unstable_mockModule('chalk', () => ({
 56 | 	default: {
 57 | 		green: jest.fn((text) => text),
 58 | 		cyan: jest.fn((text) => text),
 59 | 		bold: jest.fn((text) => text)
 60 | 	}
 61 | }));
 62 | 
 63 | jest.unstable_mockModule('boxen', () => ({
 64 | 	default: jest.fn((text) => text)
 65 | }));
 66 | 
 67 | // Import the mocked modules
 68 | const { readJSON, writeJSON, log, taskExists } = await import(
 69 | 	'../../../../../scripts/modules/utils.js'
 70 | );
 71 | 
 72 | // Import the module under test
 73 | const { fixDependenciesCommand } = await import(
 74 | 	'../../../../../scripts/modules/dependency-manager.js'
 75 | );
 76 | 
 77 | describe('fixDependenciesCommand tag preservation', () => {
 78 | 	beforeEach(() => {
 79 | 		jest.clearAllMocks();
 80 | 		mockProcessExit.mockClear();
 81 | 	});
 82 | 
 83 | 	afterAll(() => {
 84 | 		// Restore original process.exit
 85 | 		process.exit = originalExit;
 86 | 	});
 87 | 
 88 | 	it('calls writeJSON with projectRoot and tag parameters when changes are made', async () => {
 89 | 		const tasksPath = '/mock/tasks.json';
 90 | 		const projectRoot = '/mock/project/root';
 91 | 		const tag = 'master';
 92 | 
 93 | 		// Mock data WITH dependency issues to trigger writeJSON
 94 | 		const tasksDataWithIssues = {
 95 | 			tasks: [
 96 | 				{
 97 | 					id: 1,
 98 | 					title: 'Task 1',
 99 | 					dependencies: [999] // Non-existent dependency to trigger fix
100 | 				},
101 | 				{
102 | 					id: 2,
103 | 					title: 'Task 2',
104 | 					dependencies: []
105 | 				}
106 | 			],
107 | 			tag: 'master',
108 | 			_rawTaggedData: {
109 | 				master: {
110 | 					tasks: [
111 | 						{
112 | 							id: 1,
113 | 							title: 'Task 1',
114 | 							dependencies: [999]
115 | 						}
116 | 					]
117 | 				}
118 | 			}
119 | 		};
120 | 
121 | 		readJSON.mockReturnValue(tasksDataWithIssues);
122 | 		taskExists.mockReturnValue(false); // Make dependency invalid to trigger fix
123 | 
124 | 		await fixDependenciesCommand(tasksPath, {
125 | 			context: { projectRoot, tag }
126 | 		});
127 | 
128 | 		// Verify readJSON was called with correct parameters
129 | 		expect(readJSON).toHaveBeenCalledWith(tasksPath, projectRoot, tag);
130 | 
131 | 		// Verify writeJSON was called (should be triggered by removing invalid dependency)
132 | 		expect(writeJSON).toHaveBeenCalled();
133 | 
134 | 		// Check the writeJSON call parameters
135 | 		const writeJSONCalls = writeJSON.mock.calls;
136 | 		const lastWriteCall = writeJSONCalls[writeJSONCalls.length - 1];
137 | 		const [calledPath, _data, calledProjectRoot, calledTag] = lastWriteCall;
138 | 
139 | 		expect(calledPath).toBe(tasksPath);
140 | 		expect(calledProjectRoot).toBe(projectRoot);
141 | 		expect(calledTag).toBe(tag);
142 | 
143 | 		// Verify process.exit was NOT called (meaning the function succeeded)
144 | 		expect(mockProcessExit).not.toHaveBeenCalled();
145 | 	});
146 | 
147 | 	it('does not call writeJSON when no changes are needed', async () => {
148 | 		const tasksPath = '/mock/tasks.json';
149 | 		const projectRoot = '/mock/project/root';
150 | 		const tag = 'master';
151 | 
152 | 		// Mock data WITHOUT dependency issues (no changes needed)
153 | 		const cleanTasksData = {
154 | 			tasks: [
155 | 				{
156 | 					id: 1,
157 | 					title: 'Task 1',
158 | 					dependencies: [] // Clean, no issues
159 | 				}
160 | 			],
161 | 			tag: 'master'
162 | 		};
163 | 
164 | 		readJSON.mockReturnValue(cleanTasksData);
165 | 		taskExists.mockReturnValue(true); // All dependencies exist
166 | 
167 | 		await fixDependenciesCommand(tasksPath, {
168 | 			context: { projectRoot, tag }
169 | 		});
170 | 
171 | 		// Verify readJSON was called
172 | 		expect(readJSON).toHaveBeenCalledWith(tasksPath, projectRoot, tag);
173 | 
174 | 		// Verify writeJSON was NOT called (no changes needed)
175 | 		expect(writeJSON).not.toHaveBeenCalled();
176 | 
177 | 		// Verify process.exit was NOT called
178 | 		expect(mockProcessExit).not.toHaveBeenCalled();
179 | 	});
180 | 
181 | 	it('handles early exit when no valid tasks found', async () => {
182 | 		const tasksPath = '/mock/tasks.json';
183 | 
184 | 		// Mock invalid data to trigger early exit
185 | 		readJSON.mockReturnValue(null);
186 | 
187 | 		await fixDependenciesCommand(tasksPath, {
188 | 			context: { projectRoot: '/mock', tag: 'master' }
189 | 		});
190 | 
191 | 		// Verify readJSON was called
192 | 		expect(readJSON).toHaveBeenCalled();
193 | 
194 | 		// Verify writeJSON was NOT called (early exit)
195 | 		expect(writeJSON).not.toHaveBeenCalled();
196 | 
197 | 		// Verify process.exit WAS called due to invalid data
198 | 		expect(mockProcessExit).toHaveBeenCalledWith(1);
199 | 	});
200 | });
201 | 
```

--------------------------------------------------------------------------------
/src/profiles/zed.js:
--------------------------------------------------------------------------------

```javascript
  1 | // Zed profile for rule-transformer
  2 | import path from 'path';
  3 | import fs from 'fs';
  4 | import { isSilentMode, log } from '../../scripts/modules/utils.js';
  5 | import { createProfile } from './base-profile.js';
  6 | 
  7 | /**
  8 |  * Transform standard MCP config format to Zed format
  9 |  * @param {Object} mcpConfig - Standard MCP configuration object
 10 |  * @returns {Object} - Transformed Zed configuration object
 11 |  */
 12 | function transformToZedFormat(mcpConfig) {
 13 | 	const zedConfig = {};
 14 | 
 15 | 	// Transform mcpServers to context_servers
 16 | 	if (mcpConfig.mcpServers) {
 17 | 		zedConfig['context_servers'] = mcpConfig.mcpServers;
 18 | 	}
 19 | 
 20 | 	// Preserve any other existing settings
 21 | 	for (const [key, value] of Object.entries(mcpConfig)) {
 22 | 		if (key !== 'mcpServers') {
 23 | 			zedConfig[key] = value;
 24 | 		}
 25 | 	}
 26 | 
 27 | 	return zedConfig;
 28 | }
 29 | 
 30 | // Lifecycle functions for Zed profile
 31 | function onAddRulesProfile(targetDir, assetsDir) {
 32 | 	// MCP transformation will be handled in onPostConvertRulesProfile
 33 | 	// File copying is handled by the base profile via fileMap
 34 | }
 35 | 
 36 | function onRemoveRulesProfile(targetDir) {
 37 | 	// Clean up .rules (Zed uses .rules directly in root)
 38 | 	const userRulesFile = path.join(targetDir, '.rules');
 39 | 
 40 | 	try {
 41 | 		// Remove Task Master .rules
 42 | 		if (fs.existsSync(userRulesFile)) {
 43 | 			fs.rmSync(userRulesFile, { force: true });
 44 | 			log('debug', `[Zed] Removed ${userRulesFile}`);
 45 | 		}
 46 | 	} catch (err) {
 47 | 		log('error', `[Zed] Failed to remove Zed instructions: ${err.message}`);
 48 | 	}
 49 | 
 50 | 	// MCP Removal: Remove context_servers section
 51 | 	const mcpConfigPath = path.join(targetDir, '.zed', 'settings.json');
 52 | 
 53 | 	if (!fs.existsSync(mcpConfigPath)) {
 54 | 		log('debug', '[Zed] No .zed/settings.json found to clean up');
 55 | 		return;
 56 | 	}
 57 | 
 58 | 	try {
 59 | 		// Read the current config
 60 | 		const configContent = fs.readFileSync(mcpConfigPath, 'utf8');
 61 | 		const config = JSON.parse(configContent);
 62 | 
 63 | 		// Check if it has the context_servers section and task-master-ai server
 64 | 		if (
 65 | 			config['context_servers'] &&
 66 | 			config['context_servers']['task-master-ai']
 67 | 		) {
 68 | 			// Remove task-master-ai server
 69 | 			delete config['context_servers']['task-master-ai'];
 70 | 
 71 | 			// Check if there are other MCP servers in context_servers
 72 | 			const remainingServers = Object.keys(config['context_servers']);
 73 | 
 74 | 			if (remainingServers.length === 0) {
 75 | 				// No other servers, remove entire context_servers section
 76 | 				delete config['context_servers'];
 77 | 				log('debug', '[Zed] Removed empty context_servers section');
 78 | 			}
 79 | 
 80 | 			// Check if config is now empty
 81 | 			const remainingKeys = Object.keys(config);
 82 | 
 83 | 			if (remainingKeys.length === 0) {
 84 | 				// Config is empty, remove entire file
 85 | 				fs.rmSync(mcpConfigPath, { force: true });
 86 | 				log('info', '[Zed] Removed empty settings.json file');
 87 | 
 88 | 				// Check if .zed directory is empty
 89 | 				const zedDirPath = path.join(targetDir, '.zed');
 90 | 				if (fs.existsSync(zedDirPath)) {
 91 | 					const remainingContents = fs.readdirSync(zedDirPath);
 92 | 					if (remainingContents.length === 0) {
 93 | 						fs.rmSync(zedDirPath, { recursive: true, force: true });
 94 | 						log('debug', '[Zed] Removed empty .zed directory');
 95 | 					}
 96 | 				}
 97 | 			} else {
 98 | 				// Write back the modified config
 99 | 				fs.writeFileSync(
100 | 					mcpConfigPath,
101 | 					JSON.stringify(config, null, '\t') + '\n'
102 | 				);
103 | 				log(
104 | 					'info',
105 | 					'[Zed] Removed TaskMaster from settings.json, preserved other configurations'
106 | 				);
107 | 			}
108 | 		} else {
109 | 			log('debug', '[Zed] TaskMaster not found in context_servers');
110 | 		}
111 | 	} catch (error) {
112 | 		log('error', `[Zed] Failed to clean up settings.json: ${error.message}`);
113 | 	}
114 | }
115 | 
116 | function onPostConvertRulesProfile(targetDir, assetsDir) {
117 | 	// Handle .rules setup (same as onAddRulesProfile)
118 | 	onAddRulesProfile(targetDir, assetsDir);
119 | 
120 | 	// Transform MCP config to Zed format
121 | 	const mcpConfigPath = path.join(targetDir, '.zed', 'settings.json');
122 | 
123 | 	if (!fs.existsSync(mcpConfigPath)) {
124 | 		log('debug', '[Zed] No .zed/settings.json found to transform');
125 | 		return;
126 | 	}
127 | 
128 | 	try {
129 | 		// Read the generated standard MCP config
130 | 		const mcpConfigContent = fs.readFileSync(mcpConfigPath, 'utf8');
131 | 		const mcpConfig = JSON.parse(mcpConfigContent);
132 | 
133 | 		// Check if it's already in Zed format (has context_servers)
134 | 		if (mcpConfig['context_servers']) {
135 | 			log(
136 | 				'info',
137 | 				'[Zed] settings.json already in Zed format, skipping transformation'
138 | 			);
139 | 			return;
140 | 		}
141 | 
142 | 		// Transform to Zed format
143 | 		const zedConfig = transformToZedFormat(mcpConfig);
144 | 
145 | 		// Add "source": "custom" to task-master-ai server for Zed
146 | 		if (
147 | 			zedConfig['context_servers'] &&
148 | 			zedConfig['context_servers']['task-master-ai']
149 | 		) {
150 | 			zedConfig['context_servers']['task-master-ai'].source = 'custom';
151 | 		}
152 | 
153 | 		// Write back the transformed config with proper formatting
154 | 		fs.writeFileSync(
155 | 			mcpConfigPath,
156 | 			JSON.stringify(zedConfig, null, '\t') + '\n'
157 | 		);
158 | 
159 | 		log('info', '[Zed] Transformed settings.json to Zed format');
160 | 		log('debug', '[Zed] Renamed mcpServers to context_servers');
161 | 	} catch (error) {
162 | 		log('error', `[Zed] Failed to transform settings.json: ${error.message}`);
163 | 	}
164 | }
165 | 
166 | // Create and export zed profile using the base factory
167 | export const zedProfile = createProfile({
168 | 	name: 'zed',
169 | 	displayName: 'Zed',
170 | 	url: 'zed.dev',
171 | 	docsUrl: 'zed.dev/docs',
172 | 	profileDir: '.zed',
173 | 	rulesDir: '.',
174 | 	mcpConfig: true,
175 | 	mcpConfigName: 'settings.json',
176 | 	includeDefaultRules: false,
177 | 	fileMap: {
178 | 		'AGENTS.md': '.rules'
179 | 	},
180 | 	onAdd: onAddRulesProfile,
181 | 	onRemove: onRemoveRulesProfile,
182 | 	onPostConvert: onPostConvertRulesProfile
183 | });
184 | 
185 | // Export lifecycle functions separately to avoid naming conflicts
186 | export { onAddRulesProfile, onRemoveRulesProfile, onPostConvertRulesProfile };
187 | 
```

--------------------------------------------------------------------------------
/apps/cli/src/utils/auto-update.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @fileoverview Auto-update utilities for task-master-ai CLI
  3 |  */
  4 | 
  5 | import { spawn } from 'child_process';
  6 | import https from 'https';
  7 | import chalk from 'chalk';
  8 | import ora from 'ora';
  9 | import boxen from 'boxen';
 10 | 
 11 | export interface UpdateInfo {
 12 | 	currentVersion: string;
 13 | 	latestVersion: string;
 14 | 	needsUpdate: boolean;
 15 | }
 16 | 
 17 | /**
 18 |  * Get current version from build-time injected environment variable
 19 |  */
 20 | function getCurrentVersion(): string {
 21 | 	// Version is injected at build time via TM_PUBLIC_VERSION
 22 | 	const version = process.env.TM_PUBLIC_VERSION;
 23 | 	if (version && version !== 'unknown') {
 24 | 		return version;
 25 | 	}
 26 | 
 27 | 	// Fallback for development or if injection failed
 28 | 	console.warn('Could not read version from TM_PUBLIC_VERSION, using fallback');
 29 | 	return '0.0.0';
 30 | }
 31 | 
 32 | /**
 33 |  * Compare semantic versions with proper pre-release handling
 34 |  * @param v1 - First version
 35 |  * @param v2 - Second version
 36 |  * @returns -1 if v1 < v2, 0 if v1 = v2, 1 if v1 > v2
 37 |  */
 38 | export function compareVersions(v1: string, v2: string): number {
 39 | 	const toParts = (v: string) => {
 40 | 		const [core, pre = ''] = v.split('-', 2);
 41 | 		const nums = core.split('.').map((n) => Number.parseInt(n, 10) || 0);
 42 | 		return { nums, pre };
 43 | 	};
 44 | 
 45 | 	const a = toParts(v1);
 46 | 	const b = toParts(v2);
 47 | 	const len = Math.max(a.nums.length, b.nums.length);
 48 | 
 49 | 	// Compare numeric parts
 50 | 	for (let i = 0; i < len; i++) {
 51 | 		const d = (a.nums[i] || 0) - (b.nums[i] || 0);
 52 | 		if (d !== 0) return d < 0 ? -1 : 1;
 53 | 	}
 54 | 
 55 | 	// Handle pre-release comparison
 56 | 	if (a.pre && !b.pre) return -1; // prerelease < release
 57 | 	if (!a.pre && b.pre) return 1; // release > prerelease
 58 | 	if (a.pre === b.pre) return 0; // same or both empty
 59 | 	return a.pre < b.pre ? -1 : 1; // basic prerelease tie-break
 60 | }
 61 | 
 62 | /**
 63 |  * Check for newer version of task-master-ai
 64 |  */
 65 | export async function checkForUpdate(
 66 | 	currentVersionOverride?: string
 67 | ): Promise<UpdateInfo> {
 68 | 	const currentVersion = currentVersionOverride || getCurrentVersion();
 69 | 
 70 | 	return new Promise((resolve) => {
 71 | 		const options = {
 72 | 			hostname: 'registry.npmjs.org',
 73 | 			path: '/task-master-ai',
 74 | 			method: 'GET',
 75 | 			headers: {
 76 | 				Accept: 'application/vnd.npm.install-v1+json',
 77 | 				'User-Agent': `task-master-ai/${currentVersion}`
 78 | 			}
 79 | 		};
 80 | 
 81 | 		const req = https.request(options, (res) => {
 82 | 			let data = '';
 83 | 
 84 | 			res.on('data', (chunk) => {
 85 | 				data += chunk;
 86 | 			});
 87 | 
 88 | 			res.on('end', () => {
 89 | 				try {
 90 | 					if (res.statusCode !== 200)
 91 | 						throw new Error(`npm registry status ${res.statusCode}`);
 92 | 					const npmData = JSON.parse(data);
 93 | 					const latestVersion = npmData['dist-tags']?.latest || currentVersion;
 94 | 
 95 | 					const needsUpdate =
 96 | 						compareVersions(currentVersion, latestVersion) < 0;
 97 | 
 98 | 					resolve({
 99 | 						currentVersion,
100 | 						latestVersion,
101 | 						needsUpdate
102 | 					});
103 | 				} catch (error) {
104 | 					resolve({
105 | 						currentVersion,
106 | 						latestVersion: currentVersion,
107 | 						needsUpdate: false
108 | 					});
109 | 				}
110 | 			});
111 | 		});
112 | 
113 | 		req.on('error', () => {
114 | 			resolve({
115 | 				currentVersion,
116 | 				latestVersion: currentVersion,
117 | 				needsUpdate: false
118 | 			});
119 | 		});
120 | 
121 | 		req.setTimeout(3000, () => {
122 | 			req.destroy();
123 | 			resolve({
124 | 				currentVersion,
125 | 				latestVersion: currentVersion,
126 | 				needsUpdate: false
127 | 			});
128 | 		});
129 | 
130 | 		req.end();
131 | 	});
132 | }
133 | 
134 | /**
135 |  * Display upgrade notification message
136 |  */
137 | export function displayUpgradeNotification(
138 | 	currentVersion: string,
139 | 	latestVersion: string
140 | ) {
141 | 	const message = boxen(
142 | 		`${chalk.blue.bold('Update Available!')} ${chalk.dim(currentVersion)} → ${chalk.green(latestVersion)}\n\n` +
143 | 			`Auto-updating to the latest version with new features and bug fixes...`,
144 | 		{
145 | 			padding: 1,
146 | 			margin: { top: 1, bottom: 1 },
147 | 			borderColor: 'yellow',
148 | 			borderStyle: 'round'
149 | 		}
150 | 	);
151 | 
152 | 	console.log(message);
153 | }
154 | 
155 | /**
156 |  * Automatically update task-master-ai to the latest version
157 |  */
158 | export async function performAutoUpdate(
159 | 	latestVersion: string
160 | ): Promise<boolean> {
161 | 	if (process.env.TASKMASTER_SKIP_AUTO_UPDATE === '1' || process.env.CI) {
162 | 		console.log(
163 | 			chalk.dim('Skipping auto-update (TASKMASTER_SKIP_AUTO_UPDATE/CI).')
164 | 		);
165 | 		return false;
166 | 	}
167 | 	const spinner = ora({
168 | 		text: chalk.blue(
169 | 			`Updating task-master-ai to version ${chalk.green(latestVersion)}`
170 | 		),
171 | 		spinner: 'dots',
172 | 		color: 'blue'
173 | 	}).start();
174 | 
175 | 	return new Promise((resolve) => {
176 | 		const updateProcess = spawn(
177 | 			'npm',
178 | 			[
179 | 				'install',
180 | 				'-g',
181 | 				`task-master-ai@${latestVersion}`,
182 | 				'--no-fund',
183 | 				'--no-audit',
184 | 				'--loglevel=warn'
185 | 			],
186 | 			{
187 | 				stdio: ['ignore', 'pipe', 'pipe']
188 | 			}
189 | 		);
190 | 
191 | 		let errorOutput = '';
192 | 
193 | 		updateProcess.stdout.on('data', () => {
194 | 			// Update spinner text with progress
195 | 			spinner.text = chalk.blue(
196 | 				`Installing task-master-ai@${latestVersion}...`
197 | 			);
198 | 		});
199 | 
200 | 		updateProcess.stderr.on('data', (data) => {
201 | 			errorOutput += data.toString();
202 | 		});
203 | 
204 | 		updateProcess.on('close', (code) => {
205 | 			if (code === 0) {
206 | 				spinner.succeed(
207 | 					chalk.green(
208 | 						`Successfully updated to version ${chalk.bold(latestVersion)}`
209 | 					)
210 | 				);
211 | 				console.log(
212 | 					chalk.dim('Please restart your command to use the new version.')
213 | 				);
214 | 				resolve(true);
215 | 			} else {
216 | 				spinner.fail(chalk.red('Auto-update failed'));
217 | 				console.log(
218 | 					chalk.cyan(
219 | 						`Please run manually: npm install -g task-master-ai@${latestVersion}`
220 | 					)
221 | 				);
222 | 				if (errorOutput) {
223 | 					console.log(chalk.dim(`Error: ${errorOutput.trim()}`));
224 | 				}
225 | 				resolve(false);
226 | 			}
227 | 		});
228 | 
229 | 		updateProcess.on('error', (error) => {
230 | 			spinner.fail(chalk.red('Auto-update failed'));
231 | 			console.log(chalk.red('Error:'), error.message);
232 | 			console.log(
233 | 				chalk.cyan(
234 | 					`Please run manually: npm install -g task-master-ai@${latestVersion}`
235 | 				)
236 | 			);
237 | 			resolve(false);
238 | 		});
239 | 	});
240 | }
241 | 
```

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

```markdown
  1 | ---
  2 | title: Advanced Tasks
  3 | sidebarTitle: "Advanced Tasks"
  4 | ---
  5 | 
  6 | ## AI-Driven Development Workflow
  7 | 
  8 | The Cursor agent is pre-configured (via the rules file) to follow this workflow:
  9 | 
 10 | ### 1. Task Discovery and Selection
 11 | 
 12 | Ask the agent to list available tasks:
 13 | 
 14 | ```
 15 | What tasks are available to work on next?
 16 | ```
 17 | 
 18 | ```
 19 | Can you show me tasks 1, 3, and 5 to understand their current status?
 20 | ```
 21 | 
 22 | The agent will:
 23 | 
 24 | - Run `task-master list` to see all tasks
 25 | - Run `task-master next` to determine the next task to work on
 26 | - Run `task-master show 1,3,5` to display multiple tasks with interactive options
 27 | - Analyze dependencies to determine which tasks are ready to be worked on
 28 | - Prioritize tasks based on priority level and ID order
 29 | - Suggest the next task(s) to implement
 30 | 
 31 | ### 2. Task Implementation
 32 | 
 33 | When implementing a task, the agent will:
 34 | 
 35 | - Reference the task's details section for implementation specifics
 36 | - Consider dependencies on previous tasks
 37 | - Follow the project's coding standards
 38 | - Create appropriate tests based on the task's testStrategy
 39 | 
 40 | You can ask:
 41 | 
 42 | ```
 43 | Let's implement task 3. What does it involve?
 44 | ```
 45 | 
 46 | ### 2.1. Viewing Multiple Tasks
 47 | 
 48 | For efficient context gathering and batch operations:
 49 | 
 50 | ```
 51 | Show me tasks 5, 7, and 9 so I can plan my implementation approach.
 52 | ```
 53 | 
 54 | The agent will:
 55 | 
 56 | - Run `task-master show 5,7,9` to display a compact summary table
 57 | - Show task status, priority, and progress indicators
 58 | - Provide an interactive action menu with batch operations
 59 | - Allow you to perform group actions like marking multiple tasks as in-progress
 60 | 
 61 | ### 3. Task Verification
 62 | 
 63 | Before marking a task as complete, verify it according to:
 64 | 
 65 | - The task's specified testStrategy
 66 | - Any automated tests in the codebase
 67 | - Manual verification if required
 68 | 
 69 | ### 4. Task Completion
 70 | 
 71 | When a task is completed, tell the agent:
 72 | 
 73 | ```
 74 | Task 3 is now complete. Please update its status.
 75 | ```
 76 | 
 77 | The agent will execute:
 78 | 
 79 | ```bash
 80 | task-master set-status --id=3 --status=done
 81 | ```
 82 | 
 83 | ### 5. Handling Implementation Drift
 84 | 
 85 | If during implementation, you discover that:
 86 | 
 87 | - The current approach differs significantly from what was planned
 88 | - Future tasks need to be modified due to current implementation choices
 89 | - New dependencies or requirements have emerged
 90 | 
 91 | Tell the agent:
 92 | 
 93 | ```
 94 | We've decided to use MongoDB instead of PostgreSQL. Can you update all future tasks (from ID 4) to reflect this change?
 95 | ```
 96 | 
 97 | The agent will execute:
 98 | 
 99 | ```bash
100 | task-master update --from=4 --prompt="Now we are using MongoDB instead of PostgreSQL."
101 | 
102 | # OR, if research is needed to find best practices for MongoDB:
103 | task-master update --from=4 --prompt="Update to use MongoDB, researching best practices" --research
104 | ```
105 | 
106 | This will rewrite or re-scope subsequent tasks in tasks.json while preserving completed work.
107 | 
108 | ### 6. Reorganizing Tasks
109 | 
110 | If you need to reorganize your task structure:
111 | 
112 | ```
113 | I think subtask 5.2 would fit better as part of task 7 instead. Can you move it there?
114 | ```
115 | 
116 | The agent will execute:
117 | 
118 | ```bash
119 | task-master move --from=5.2 --to=7.3
120 | ```
121 | 
122 | You can reorganize tasks in various ways:
123 | 
124 | - Moving a standalone task to become a subtask: `--from=5 --to=7`
125 | - Moving a subtask to become a standalone task: `--from=5.2 --to=7`
126 | - Moving a subtask to a different parent: `--from=5.2 --to=7.3`
127 | - Reordering subtasks within the same parent: `--from=5.2 --to=5.4`
128 | - Moving a task to a new ID position: `--from=5 --to=25` (even if task 25 doesn't exist yet)
129 | - 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)
130 | 
131 | When moving tasks to new IDs:
132 | 
133 | - The system automatically creates placeholder tasks for non-existent destination IDs
134 | - This prevents accidental data loss during reorganization
135 | - Any tasks that depend on moved tasks will have their dependencies updated
136 | - When moving a parent task, all its subtasks are automatically moved with it and renumbered
137 | 
138 | This is particularly useful as your project understanding evolves and you need to refine your task structure.
139 | 
140 | ### 7. Resolving Merge Conflicts with Tasks
141 | 
142 | 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:
143 | 
144 | ```
145 | 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?
146 | ```
147 | 
148 | The agent will help you:
149 | 
150 | 1. Keep your teammates' tasks (10-15)
151 | 2. Move your tasks to new positions to avoid conflicts:
152 | 
153 | ```bash
154 | # Move your tasks to new positions (e.g., 16-18)
155 | task-master move --from=10 --to=16
156 | task-master move --from=11 --to=17
157 | task-master move --from=12 --to=18
158 | ```
159 | 
160 | 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.
161 | 
162 | ### 8. Breaking Down Complex Tasks
163 | 
164 | For complex tasks that need more granularity:
165 | 
166 | ```
167 | Task 5 seems complex. Can you break it down into subtasks?
168 | ```
169 | 
170 | The agent will execute:
171 | 
172 | ```bash
173 | task-master expand --id=5 --num=3
174 | ```
175 | 
176 | You can provide additional context:
177 | 
178 | ```
179 | Please break down task 5 with a focus on security considerations.
180 | ```
181 | 
182 | The agent will execute:
183 | 
184 | ```bash
185 | task-master expand --id=5 --prompt="Focus on security aspects"
186 | ```
187 | 
188 | You can also expand all pending tasks:
189 | 
190 | ```
191 | Please break down all pending tasks into subtasks.
192 | ```
193 | 
194 | The agent will execute:
195 | 
196 | ```bash
197 | task-master expand --all
198 | ```
199 | 
200 | For research-backed subtask generation using the configured research model:
201 | 
202 | ```
203 | Please break down task 5 using research-backed generation.
204 | ```
205 | 
206 | The agent will execute:
207 | 
208 | ```bash
209 | task-master expand --id=5 --research
210 | ```
```

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

```typescript
  1 | /**
  2 |  * @fileoverview Format handler for task storage files
  3 |  */
  4 | 
  5 | import type { Task, TaskMetadata } from '../../types/index.js';
  6 | 
  7 | export interface FileStorageData {
  8 | 	tasks: Task[];
  9 | 	metadata: TaskMetadata;
 10 | }
 11 | 
 12 | export type FileFormat = 'legacy' | 'standard';
 13 | 
 14 | /**
 15 |  * Handles format detection and conversion between legacy and standard task file formats
 16 |  */
 17 | export class FormatHandler {
 18 | 	/**
 19 | 	 * Detect the format of the raw data
 20 | 	 */
 21 | 	detectFormat(data: any): FileFormat {
 22 | 		if (!data || typeof data !== 'object') {
 23 | 			return 'standard';
 24 | 		}
 25 | 
 26 | 		const keys = Object.keys(data);
 27 | 
 28 | 		// Check if this uses the legacy format with tag keys
 29 | 		// Legacy format has keys that are not 'tasks' or 'metadata'
 30 | 		const hasLegacyFormat = keys.some(
 31 | 			(key) => key !== 'tasks' && key !== 'metadata'
 32 | 		);
 33 | 
 34 | 		return hasLegacyFormat ? 'legacy' : 'standard';
 35 | 	}
 36 | 
 37 | 	/**
 38 | 	 * Extract tasks from data for a specific tag
 39 | 	 */
 40 | 	extractTasks(data: any, tag: string): Task[] {
 41 | 		if (!data) {
 42 | 			return [];
 43 | 		}
 44 | 
 45 | 		const format = this.detectFormat(data);
 46 | 
 47 | 		if (format === 'legacy') {
 48 | 			return this.extractTasksFromLegacy(data, tag);
 49 | 		}
 50 | 
 51 | 		return this.extractTasksFromStandard(data);
 52 | 	}
 53 | 
 54 | 	/**
 55 | 	 * Extract tasks from legacy format
 56 | 	 */
 57 | 	private extractTasksFromLegacy(data: any, tag: string): Task[] {
 58 | 		// First check if the requested tag exists
 59 | 		if (tag in data) {
 60 | 			const tagData = data[tag];
 61 | 			return tagData?.tasks || [];
 62 | 		}
 63 | 
 64 | 		// If we're looking for 'master' tag but it doesn't exist, try the first available tag
 65 | 		const availableKeys = Object.keys(data).filter(
 66 | 			(key) => key !== 'tasks' && key !== 'metadata'
 67 | 		);
 68 | 		if (tag === 'master' && availableKeys.length > 0) {
 69 | 			const firstTag = availableKeys[0];
 70 | 			const tagData = data[firstTag];
 71 | 			return tagData?.tasks || [];
 72 | 		}
 73 | 
 74 | 		return [];
 75 | 	}
 76 | 
 77 | 	/**
 78 | 	 * Extract tasks from standard format
 79 | 	 */
 80 | 	private extractTasksFromStandard(data: any): Task[] {
 81 | 		return data?.tasks || [];
 82 | 	}
 83 | 
 84 | 	/**
 85 | 	 * Extract metadata from data for a specific tag
 86 | 	 */
 87 | 	extractMetadata(data: any, tag: string): TaskMetadata | null {
 88 | 		if (!data) {
 89 | 			return null;
 90 | 		}
 91 | 
 92 | 		const format = this.detectFormat(data);
 93 | 
 94 | 		if (format === 'legacy') {
 95 | 			return this.extractMetadataFromLegacy(data, tag);
 96 | 		}
 97 | 
 98 | 		return this.extractMetadataFromStandard(data);
 99 | 	}
100 | 
101 | 	/**
102 | 	 * Extract metadata from legacy format
103 | 	 */
104 | 	private extractMetadataFromLegacy(
105 | 		data: any,
106 | 		tag: string
107 | 	): TaskMetadata | null {
108 | 		if (tag in data) {
109 | 			const tagData = data[tag];
110 | 			// Generate metadata if not present in legacy format
111 | 			if (!tagData?.metadata && tagData?.tasks) {
112 | 				return this.generateMetadataFromTasks(tagData.tasks, tag);
113 | 			}
114 | 			return tagData?.metadata || null;
115 | 		}
116 | 
117 | 		// If we're looking for 'master' tag but it doesn't exist, try the first available tag
118 | 		const availableKeys = Object.keys(data).filter(
119 | 			(key) => key !== 'tasks' && key !== 'metadata'
120 | 		);
121 | 		if (tag === 'master' && availableKeys.length > 0) {
122 | 			const firstTag = availableKeys[0];
123 | 			const tagData = data[firstTag];
124 | 			if (!tagData?.metadata && tagData?.tasks) {
125 | 				return this.generateMetadataFromTasks(tagData.tasks, firstTag);
126 | 			}
127 | 			return tagData?.metadata || null;
128 | 		}
129 | 
130 | 		return null;
131 | 	}
132 | 
133 | 	/**
134 | 	 * Extract metadata from standard format
135 | 	 */
136 | 	private extractMetadataFromStandard(data: any): TaskMetadata | null {
137 | 		return data?.metadata || null;
138 | 	}
139 | 
140 | 	/**
141 | 	 * Extract all available tags from the single tasks.json file
142 | 	 */
143 | 	extractTags(data: any): string[] {
144 | 		if (!data) {
145 | 			return [];
146 | 		}
147 | 
148 | 		const format = this.detectFormat(data);
149 | 
150 | 		if (format === 'legacy') {
151 | 			// Return all tag keys from legacy format
152 | 			const keys = Object.keys(data);
153 | 			return keys.filter((key) => key !== 'tasks' && key !== 'metadata');
154 | 		}
155 | 
156 | 		// Standard format - just has 'master' tag
157 | 		return ['master'];
158 | 	}
159 | 
160 | 	/**
161 | 	 * Convert tasks and metadata to the appropriate format for saving
162 | 	 */
163 | 	convertToSaveFormat(
164 | 		tasks: Task[],
165 | 		metadata: TaskMetadata,
166 | 		existingData: any,
167 | 		tag: string
168 | 	): any {
169 | 		const resolvedTag = tag || 'master';
170 | 
171 | 		// Normalize task IDs to strings
172 | 		const normalizedTasks = this.normalizeTasks(tasks);
173 | 
174 | 		// Check if existing file uses legacy format
175 | 		if (existingData && this.detectFormat(existingData) === 'legacy') {
176 | 			return this.convertToLegacyFormat(normalizedTasks, metadata, resolvedTag);
177 | 		}
178 | 
179 | 		// Use standard format for new files
180 | 		return this.convertToStandardFormat(normalizedTasks, metadata, tag);
181 | 	}
182 | 
183 | 	/**
184 | 	 * Convert to legacy format
185 | 	 */
186 | 	private convertToLegacyFormat(
187 | 		tasks: Task[],
188 | 		metadata: TaskMetadata,
189 | 		tag: string
190 | 	): any {
191 | 		return {
192 | 			[tag]: {
193 | 				tasks,
194 | 				metadata: {
195 | 					...metadata,
196 | 					tags: [tag]
197 | 				}
198 | 			}
199 | 		};
200 | 	}
201 | 
202 | 	/**
203 | 	 * Convert to standard format
204 | 	 */
205 | 	private convertToStandardFormat(
206 | 		tasks: Task[],
207 | 		metadata: TaskMetadata,
208 | 		tag?: string
209 | 	): FileStorageData {
210 | 		return {
211 | 			tasks,
212 | 			metadata: {
213 | 				...metadata,
214 | 				tags: tag ? [tag] : []
215 | 			}
216 | 		};
217 | 	}
218 | 
219 | 	/**
220 | 	 * Normalize task IDs - keep Task IDs as strings, Subtask IDs as numbers
221 | 	 */
222 | 	private normalizeTasks(tasks: Task[]): Task[] {
223 | 		return tasks.map((task) => ({
224 | 			...task,
225 | 			id: String(task.id), // Task IDs are strings
226 | 			dependencies: task.dependencies?.map((dep) => String(dep)) || [],
227 | 			subtasks:
228 | 				task.subtasks?.map((subtask) => ({
229 | 					...subtask,
230 | 					id: Number(subtask.id), // Subtask IDs are numbers
231 | 					parentId: String(subtask.parentId) // Parent ID is string (Task ID)
232 | 				})) || []
233 | 		}));
234 | 	}
235 | 
236 | 	/**
237 | 	 * Generate metadata from tasks when not present
238 | 	 */
239 | 	private generateMetadataFromTasks(tasks: Task[], tag: string): TaskMetadata {
240 | 		return {
241 | 			version: '1.0.0',
242 | 			lastModified: new Date().toISOString(),
243 | 			taskCount: tasks.length,
244 | 			completedCount: tasks.filter((t: any) => t.status === 'done').length,
245 | 			tags: [tag]
246 | 		};
247 | 	}
248 | }
249 | 
```

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

```typescript
  1 | /**
  2 |  * @fileoverview Unit tests for ConfigMerger service
  3 |  */
  4 | 
  5 | import { describe, it, expect, beforeEach } from 'vitest';
  6 | import { ConfigMerger, CONFIG_PRECEDENCE } from './config-merger.service.js';
  7 | 
  8 | describe('ConfigMerger', () => {
  9 | 	let merger: ConfigMerger;
 10 | 
 11 | 	beforeEach(() => {
 12 | 		merger = new ConfigMerger();
 13 | 	});
 14 | 
 15 | 	describe('addSource', () => {
 16 | 		it('should add configuration source', () => {
 17 | 			const source = {
 18 | 				name: 'test',
 19 | 				config: { test: true },
 20 | 				precedence: 1
 21 | 			};
 22 | 
 23 | 			merger.addSource(source);
 24 | 			const sources = merger.getSources();
 25 | 
 26 | 			expect(sources).toHaveLength(1);
 27 | 			expect(sources[0]).toEqual(source);
 28 | 		});
 29 | 
 30 | 		it('should add multiple sources', () => {
 31 | 			merger.addSource({ name: 'source1', config: {}, precedence: 1 });
 32 | 			merger.addSource({ name: 'source2', config: {}, precedence: 2 });
 33 | 
 34 | 			expect(merger.getSources()).toHaveLength(2);
 35 | 		});
 36 | 	});
 37 | 
 38 | 	describe('clearSources', () => {
 39 | 		it('should remove all configuration sources', () => {
 40 | 			merger.addSource({ name: 'test', config: {}, precedence: 1 });
 41 | 			merger.clearSources();
 42 | 
 43 | 			expect(merger.getSources()).toHaveLength(0);
 44 | 		});
 45 | 	});
 46 | 
 47 | 	describe('merge', () => {
 48 | 		it('should merge configurations based on precedence', () => {
 49 | 			merger.addSource({
 50 | 				name: 'low',
 51 | 				config: { a: 1, b: 2 },
 52 | 				precedence: 1
 53 | 			});
 54 | 
 55 | 			merger.addSource({
 56 | 				name: 'high',
 57 | 				config: { a: 3, c: 4 },
 58 | 				precedence: 2
 59 | 			});
 60 | 
 61 | 			const result = merger.merge();
 62 | 
 63 | 			expect(result).toEqual({
 64 | 				a: 3, // High precedence wins
 65 | 				b: 2, // Only in low
 66 | 				c: 4 // Only in high
 67 | 			});
 68 | 		});
 69 | 
 70 | 		it('should deep merge nested objects', () => {
 71 | 			merger.addSource({
 72 | 				name: 'base',
 73 | 				config: {
 74 | 					models: { main: 'model1', fallback: 'model2' },
 75 | 					storage: { type: 'file' as const }
 76 | 				},
 77 | 				precedence: 1
 78 | 			});
 79 | 
 80 | 			merger.addSource({
 81 | 				name: 'override',
 82 | 				config: {
 83 | 					models: { main: 'model3' },
 84 | 					storage: { encoding: 'utf8' as const }
 85 | 				},
 86 | 				precedence: 2
 87 | 			});
 88 | 
 89 | 			const result = merger.merge();
 90 | 
 91 | 			expect(result).toEqual({
 92 | 				models: {
 93 | 					main: 'model3', // Overridden
 94 | 					fallback: 'model2' // Preserved
 95 | 				},
 96 | 				storage: {
 97 | 					type: 'file', // Preserved
 98 | 					encoding: 'utf8' // Added
 99 | 				}
100 | 			});
101 | 		});
102 | 
103 | 		it('should handle arrays by replacement', () => {
104 | 			merger.addSource({
105 | 				name: 'base',
106 | 				config: { items: [1, 2, 3] },
107 | 				precedence: 1
108 | 			});
109 | 
110 | 			merger.addSource({
111 | 				name: 'override',
112 | 				config: { items: [4, 5] },
113 | 				precedence: 2
114 | 			});
115 | 
116 | 			const result = merger.merge();
117 | 
118 | 			expect(result.items).toEqual([4, 5]); // Arrays are replaced, not merged
119 | 		});
120 | 
121 | 		it('should ignore null and undefined values', () => {
122 | 			merger.addSource({
123 | 				name: 'base',
124 | 				config: { a: 1, b: 2 },
125 | 				precedence: 1
126 | 			});
127 | 
128 | 			merger.addSource({
129 | 				name: 'override',
130 | 				config: { a: null, b: undefined, c: 3 } as any,
131 | 				precedence: 2
132 | 			});
133 | 
134 | 			const result = merger.merge();
135 | 
136 | 			expect(result).toEqual({
137 | 				a: 1, // null ignored
138 | 				b: 2, // undefined ignored
139 | 				c: 3 // new value added
140 | 			});
141 | 		});
142 | 
143 | 		it('should return empty object when no sources', () => {
144 | 			const result = merger.merge();
145 | 			expect(result).toEqual({});
146 | 		});
147 | 
148 | 		it('should use CONFIG_PRECEDENCE constants correctly', () => {
149 | 			merger.addSource({
150 | 				name: 'defaults',
151 | 				config: { level: 'default' },
152 | 				precedence: CONFIG_PRECEDENCE.DEFAULTS
153 | 			});
154 | 
155 | 			merger.addSource({
156 | 				name: 'local',
157 | 				config: { level: 'local' },
158 | 				precedence: CONFIG_PRECEDENCE.LOCAL
159 | 			});
160 | 
161 | 			merger.addSource({
162 | 				name: 'environment',
163 | 				config: { level: 'env' },
164 | 				precedence: CONFIG_PRECEDENCE.ENVIRONMENT
165 | 			});
166 | 
167 | 			const result = merger.merge();
168 | 
169 | 			expect(result.level).toBe('env'); // Highest precedence wins
170 | 		});
171 | 	});
172 | 
173 | 	describe('getSources', () => {
174 | 		it('should return sources sorted by precedence (highest first)', () => {
175 | 			merger.addSource({ name: 'low', config: {}, precedence: 1 });
176 | 			merger.addSource({ name: 'high', config: {}, precedence: 3 });
177 | 			merger.addSource({ name: 'medium', config: {}, precedence: 2 });
178 | 
179 | 			const sources = merger.getSources();
180 | 
181 | 			expect(sources[0].name).toBe('high');
182 | 			expect(sources[1].name).toBe('medium');
183 | 			expect(sources[2].name).toBe('low');
184 | 		});
185 | 
186 | 		it('should return a copy of sources array', () => {
187 | 			merger.addSource({ name: 'test', config: {}, precedence: 1 });
188 | 
189 | 			const sources1 = merger.getSources();
190 | 			const sources2 = merger.getSources();
191 | 
192 | 			expect(sources1).not.toBe(sources2); // Different array instances
193 | 			expect(sources1).toEqual(sources2); // Same content
194 | 		});
195 | 	});
196 | 
197 | 	describe('hasSource', () => {
198 | 		it('should return true when source exists', () => {
199 | 			merger.addSource({ name: 'test', config: {}, precedence: 1 });
200 | 
201 | 			expect(merger.hasSource('test')).toBe(true);
202 | 		});
203 | 
204 | 		it('should return false when source does not exist', () => {
205 | 			expect(merger.hasSource('nonexistent')).toBe(false);
206 | 		});
207 | 	});
208 | 
209 | 	describe('removeSource', () => {
210 | 		it('should remove source by name and return true', () => {
211 | 			merger.addSource({ name: 'test', config: {}, precedence: 1 });
212 | 			merger.addSource({ name: 'keep', config: {}, precedence: 2 });
213 | 
214 | 			const removed = merger.removeSource('test');
215 | 
216 | 			expect(removed).toBe(true);
217 | 			expect(merger.hasSource('test')).toBe(false);
218 | 			expect(merger.hasSource('keep')).toBe(true);
219 | 		});
220 | 
221 | 		it('should return false when source does not exist', () => {
222 | 			const removed = merger.removeSource('nonexistent');
223 | 
224 | 			expect(removed).toBe(false);
225 | 		});
226 | 
227 | 		it('should handle removing all sources', () => {
228 | 			merger.addSource({ name: 'test1', config: {}, precedence: 1 });
229 | 			merger.addSource({ name: 'test2', config: {}, precedence: 2 });
230 | 
231 | 			merger.removeSource('test1');
232 | 			merger.removeSource('test2');
233 | 
234 | 			expect(merger.getSources()).toHaveLength(0);
235 | 		});
236 | 	});
237 | });
238 | 
```

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

```javascript
  1 | /**
  2 |  * add-task.js
  3 |  * Direct function implementation for adding a new task
  4 |  */
  5 | 
  6 | import { addTask } from '../../../../scripts/modules/task-manager.js';
  7 | import {
  8 | 	enableSilentMode,
  9 | 	disableSilentMode
 10 | } from '../../../../scripts/modules/utils.js';
 11 | import { createLogWrapper } from '../../tools/utils.js';
 12 | 
 13 | /**
 14 |  * Direct function wrapper for adding a new task with error handling.
 15 |  *
 16 |  * @param {Object} args - Command arguments
 17 |  * @param {string} [args.prompt] - Description of the task to add (required if not using manual fields)
 18 |  * @param {string} [args.title] - Task title (for manual task creation)
 19 |  * @param {string} [args.description] - Task description (for manual task creation)
 20 |  * @param {string} [args.details] - Implementation details (for manual task creation)
 21 |  * @param {string} [args.testStrategy] - Test strategy (for manual task creation)
 22 |  * @param {string} [args.dependencies] - Comma-separated list of task IDs this task depends on
 23 |  * @param {string} [args.priority='medium'] - Task priority (high, medium, low)
 24 |  * @param {string} [args.tasksJsonPath] - Path to the tasks.json file (resolved by tool)
 25 |  * @param {boolean} [args.research=false] - Whether to use research capabilities for task creation
 26 |  * @param {string} [args.projectRoot] - Project root path
 27 |  * @param {string} [args.tag] - Tag for the task (optional)
 28 |  * @param {Object} log - Logger object
 29 |  * @param {Object} context - Additional context (session)
 30 |  * @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
 31 |  */
 32 | export async function addTaskDirect(args, log, context = {}) {
 33 | 	// Destructure expected args (including research and projectRoot)
 34 | 	const {
 35 | 		tasksJsonPath,
 36 | 		prompt,
 37 | 		dependencies,
 38 | 		priority,
 39 | 		research,
 40 | 		projectRoot,
 41 | 		tag
 42 | 	} = args;
 43 | 	const { session } = context; // Destructure session from context
 44 | 
 45 | 	// Enable silent mode to prevent console logs from interfering with JSON response
 46 | 	enableSilentMode();
 47 | 
 48 | 	// Create logger wrapper using the utility
 49 | 	const mcpLog = createLogWrapper(log);
 50 | 
 51 | 	try {
 52 | 		// Check if tasksJsonPath was provided
 53 | 		if (!tasksJsonPath) {
 54 | 			log.error('addTaskDirect called without tasksJsonPath');
 55 | 			disableSilentMode(); // Disable before returning
 56 | 			return {
 57 | 				success: false,
 58 | 				error: {
 59 | 					code: 'MISSING_ARGUMENT',
 60 | 					message: 'tasksJsonPath is required'
 61 | 				}
 62 | 			};
 63 | 		}
 64 | 
 65 | 		// Use provided path
 66 | 		const tasksPath = tasksJsonPath;
 67 | 
 68 | 		// Check if this is manual task creation or AI-driven task creation
 69 | 		const isManualCreation = args.title && args.description;
 70 | 
 71 | 		// Check required parameters
 72 | 		if (!args.prompt && !isManualCreation) {
 73 | 			log.error(
 74 | 				'Missing required parameters: either prompt or title+description must be provided'
 75 | 			);
 76 | 			disableSilentMode();
 77 | 			return {
 78 | 				success: false,
 79 | 				error: {
 80 | 					code: 'MISSING_PARAMETER',
 81 | 					message:
 82 | 						'Either the prompt parameter or both title and description parameters are required for adding a task'
 83 | 				}
 84 | 			};
 85 | 		}
 86 | 
 87 | 		// Extract and prepare parameters
 88 | 		const taskDependencies = Array.isArray(dependencies)
 89 | 			? dependencies // Already an array if passed directly
 90 | 			: dependencies // Check if dependencies exist and are a string
 91 | 				? String(dependencies)
 92 | 						.split(',')
 93 | 						.map((id) => parseInt(id.trim(), 10)) // Split, trim, and parse
 94 | 				: []; // Default to empty array if null/undefined
 95 | 		const taskPriority = priority || 'medium'; // Default priority
 96 | 
 97 | 		let manualTaskData = null;
 98 | 		let newTaskId;
 99 | 		let telemetryData;
100 | 		let tagInfo;
101 | 
102 | 		if (isManualCreation) {
103 | 			// Create manual task data object
104 | 			manualTaskData = {
105 | 				title: args.title,
106 | 				description: args.description,
107 | 				details: args.details || '',
108 | 				testStrategy: args.testStrategy || ''
109 | 			};
110 | 
111 | 			log.info(
112 | 				`Adding new task manually with title: "${args.title}", dependencies: [${taskDependencies.join(', ')}], priority: ${priority}`
113 | 			);
114 | 
115 | 			// Call the addTask function with manual task data
116 | 			const result = await addTask(
117 | 				tasksPath,
118 | 				null, // prompt is null for manual creation
119 | 				taskDependencies,
120 | 				taskPriority,
121 | 				{
122 | 					session,
123 | 					mcpLog,
124 | 					projectRoot,
125 | 					commandName: 'add-task',
126 | 					outputType: 'mcp',
127 | 					tag
128 | 				},
129 | 				'json', // outputFormat
130 | 				manualTaskData, // Pass the manual task data
131 | 				false // research flag is false for manual creation
132 | 			);
133 | 			newTaskId = result.newTaskId;
134 | 			telemetryData = result.telemetryData;
135 | 			tagInfo = result.tagInfo;
136 | 		} else {
137 | 			// AI-driven task creation
138 | 			log.info(
139 | 				`Adding new task with prompt: "${prompt}", dependencies: [${taskDependencies.join(', ')}], priority: ${taskPriority}, research: ${research}`
140 | 			);
141 | 
142 | 			// Call the addTask function, passing the research flag
143 | 			const result = await addTask(
144 | 				tasksPath,
145 | 				prompt, // Use the prompt for AI creation
146 | 				taskDependencies,
147 | 				taskPriority,
148 | 				{
149 | 					session,
150 | 					mcpLog,
151 | 					projectRoot,
152 | 					commandName: 'add-task',
153 | 					outputType: 'mcp',
154 | 					tag
155 | 				},
156 | 				'json', // outputFormat
157 | 				null, // manualTaskData is null for AI creation
158 | 				research // Pass the research flag
159 | 			);
160 | 			newTaskId = result.newTaskId;
161 | 			telemetryData = result.telemetryData;
162 | 			tagInfo = result.tagInfo;
163 | 		}
164 | 
165 | 		// Restore normal logging
166 | 		disableSilentMode();
167 | 
168 | 		return {
169 | 			success: true,
170 | 			data: {
171 | 				taskId: newTaskId,
172 | 				message: `Successfully added new task #${newTaskId}`,
173 | 				telemetryData: telemetryData,
174 | 				tagInfo: tagInfo
175 | 			}
176 | 		};
177 | 	} catch (error) {
178 | 		// Make sure to restore normal logging even if there's an error
179 | 		disableSilentMode();
180 | 
181 | 		log.error(`Error in addTaskDirect: ${error.message}`);
182 | 		// Add specific error code checks if needed
183 | 		return {
184 | 			success: false,
185 | 			error: {
186 | 				code: error.code || 'ADD_TASK_ERROR', // Use error code if available
187 | 				message: error.message
188 | 			}
189 | 		};
190 | 	}
191 | }
192 | 
```

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

```javascript
  1 | import fs from 'fs';
  2 | import path from 'path';
  3 | import chalk from 'chalk';
  4 | import { log, findProjectRoot } from './utils.js';
  5 | import { getProjectName } from './config-manager.js';
  6 | import listTasks from './task-manager/list-tasks.js';
  7 | 
  8 | /**
  9 |  * Creates a basic README structure if one doesn't exist
 10 |  * @param {string} projectName - Name of the project
 11 |  * @returns {string} - Basic README content
 12 |  */
 13 | function createBasicReadme(projectName) {
 14 | 	return `# ${projectName}
 15 | 
 16 | This project is managed using Task Master.
 17 | 
 18 | `;
 19 | }
 20 | 
 21 | /**
 22 |  * Create UTM tracking URL for task-master.dev
 23 |  * @param {string} projectRoot - The project root path
 24 |  * @returns {string} - UTM tracked URL
 25 |  */
 26 | function createTaskMasterUrl(projectRoot) {
 27 | 	// Get the actual folder name from the project root path
 28 | 	const folderName = path.basename(projectRoot);
 29 | 
 30 | 	// Clean folder name for UTM (replace spaces/special chars with hyphens)
 31 | 	const cleanFolderName = folderName
 32 | 		.toLowerCase()
 33 | 		.replace(/[^a-z0-9]/g, '-')
 34 | 		.replace(/-+/g, '-')
 35 | 		.replace(/^-|-$/g, '');
 36 | 
 37 | 	const utmParams = new URLSearchParams({
 38 | 		utm_source: 'github-readme',
 39 | 		utm_medium: 'readme-export',
 40 | 		utm_campaign: cleanFolderName || 'task-sync',
 41 | 		utm_content: 'task-export-link'
 42 | 	});
 43 | 
 44 | 	return `https://task-master.dev?${utmParams.toString()}`;
 45 | }
 46 | 
 47 | /**
 48 |  * Create the start marker with metadata
 49 |  * @param {Object} options - Export options
 50 |  * @returns {string} - Formatted start marker
 51 |  */
 52 | function createStartMarker(options) {
 53 | 	const { timestamp, withSubtasks, status, projectRoot } = options;
 54 | 
 55 | 	// Format status filter text
 56 | 	const statusText = status
 57 | 		? `Status filter: ${status}`
 58 | 		: 'Status filter: none';
 59 | 	const subtasksText = withSubtasks ? 'with subtasks' : 'without subtasks';
 60 | 
 61 | 	// Create the export info content
 62 | 	const exportInfo =
 63 | 		`🎯 **Taskmaster Export** - ${timestamp}\n` +
 64 | 		`📋 Export: ${subtasksText} • ${statusText}\n` +
 65 | 		`🔗 Powered by [Task Master](${createTaskMasterUrl(projectRoot)})`;
 66 | 
 67 | 	// Create a markdown box using code blocks and emojis to mimic our UI style
 68 | 	const boxContent =
 69 | 		`<!-- TASKMASTER_EXPORT_START -->\n` +
 70 | 		`> ${exportInfo.split('\n').join('\n> ')}\n\n`;
 71 | 
 72 | 	return boxContent;
 73 | }
 74 | 
 75 | /**
 76 |  * Create the end marker
 77 |  * @returns {string} - Formatted end marker
 78 |  */
 79 | function createEndMarker() {
 80 | 	return (
 81 | 		`\n> 📋 **End of Taskmaster Export** - Tasks are synced from your project using the \`sync-readme\` command.\n` +
 82 | 		`<!-- TASKMASTER_EXPORT_END -->\n`
 83 | 	);
 84 | }
 85 | 
 86 | /**
 87 |  * Syncs the current task list to README.md at the project root
 88 |  * @param {string} projectRoot - Path to the project root directory
 89 |  * @param {Object} options - Options for syncing
 90 |  * @param {boolean} options.withSubtasks - Include subtasks in the output (default: false)
 91 |  * @param {string} options.status - Filter by status (e.g., 'pending', 'done')
 92 |  * @param {string} options.tasksPath - Custom path to tasks.json
 93 |  * @returns {boolean} - True if sync was successful, false otherwise
 94 |  * TODO: Add tag support - this is not currently supported how we want to handle this  - Parthy
 95 |  */
 96 | export async function syncTasksToReadme(projectRoot = null, options = {}) {
 97 | 	try {
 98 | 		const actualProjectRoot = projectRoot || findProjectRoot() || '.';
 99 | 		const { withSubtasks = false, status, tasksPath, tag } = options;
100 | 
101 | 		// Get current tasks using the list-tasks functionality with markdown-readme format
102 | 		const tasksOutput = await listTasks(
103 | 			tasksPath ||
104 | 				path.join(actualProjectRoot, '.taskmaster', 'tasks', 'tasks.json'),
105 | 			status,
106 | 			null,
107 | 			withSubtasks,
108 | 			'markdown-readme',
109 | 			{ projectRoot, tag }
110 | 		);
111 | 
112 | 		if (!tasksOutput) {
113 | 			console.log(chalk.red('❌ Failed to generate task output'));
114 | 			return false;
115 | 		}
116 | 
117 | 		// Generate timestamp and metadata
118 | 		const timestamp =
119 | 			new Date().toISOString().replace('T', ' ').substring(0, 19) + ' UTC';
120 | 		const projectName = getProjectName(actualProjectRoot);
121 | 
122 | 		// Create the export markers with metadata
123 | 		const startMarker = createStartMarker({
124 | 			timestamp,
125 | 			withSubtasks,
126 | 			status,
127 | 			projectRoot: actualProjectRoot
128 | 		});
129 | 
130 | 		const endMarker = createEndMarker();
131 | 
132 | 		// Create the complete task section
133 | 		const taskSection = startMarker + tasksOutput + endMarker;
134 | 
135 | 		// Read current README content
136 | 		const readmePath = path.join(actualProjectRoot, 'README.md');
137 | 		let readmeContent = '';
138 | 		try {
139 | 			readmeContent = fs.readFileSync(readmePath, 'utf8');
140 | 		} catch (err) {
141 | 			if (err.code === 'ENOENT') {
142 | 				// Create basic README if it doesn't exist
143 | 				readmeContent = createBasicReadme(projectName);
144 | 			} else {
145 | 				throw err;
146 | 			}
147 | 		}
148 | 
149 | 		// Check if export markers exist and replace content between them
150 | 		const startComment = '<!-- TASKMASTER_EXPORT_START -->';
151 | 		const endComment = '<!-- TASKMASTER_EXPORT_END -->';
152 | 
153 | 		let updatedContent;
154 | 		const startIndex = readmeContent.indexOf(startComment);
155 | 		const endIndex = readmeContent.indexOf(endComment);
156 | 
157 | 		if (startIndex !== -1 && endIndex !== -1) {
158 | 			// Replace existing task section
159 | 			const beforeTasks = readmeContent.substring(0, startIndex);
160 | 			const afterTasks = readmeContent.substring(endIndex + endComment.length);
161 | 			updatedContent = beforeTasks + taskSection + afterTasks;
162 | 		} else {
163 | 			// Append to end of README
164 | 			updatedContent = readmeContent + '\n' + taskSection;
165 | 		}
166 | 
167 | 		// Write updated content to README
168 | 		fs.writeFileSync(readmePath, updatedContent, 'utf8');
169 | 
170 | 		console.log(chalk.green('✅ Successfully synced tasks to README.md'));
171 | 		console.log(
172 | 			chalk.cyan(
173 | 				`📋 Export details: ${withSubtasks ? 'with' : 'without'} subtasks${status ? `, status: ${status}` : ''}`
174 | 			)
175 | 		);
176 | 		console.log(chalk.gray(`📍 Location: ${readmePath}`));
177 | 
178 | 		return true;
179 | 	} catch (error) {
180 | 		console.log(chalk.red('❌ Failed to sync tasks to README:'), error.message);
181 | 		log('error', `README sync error: ${error.message}`);
182 | 		return false;
183 | 	}
184 | }
185 | 
186 | export default syncTasksToReadme;
187 | 
```

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

```
 1 | <context>
 2 | # Overview
 3 | 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.
 4 | 
 5 | # Core Features
 6 | 1.  **URL Input & Shortening:** A user interface with an input field for pasting a long URL and a button to trigger the shortening process.
 7 |     -   *Why:* The primary function for the user interaction.
 8 |     -   *How:* A React component with a text input and a submit button. Clicking the button sends the long URL to a backend API.
 9 | 2.  **Short URL Display:** After successful shortening, the application displays the newly generated short URL to the user.
10 |     -   *Why:* Provides the result of the core function to the user.
11 |     -   *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.
12 | 3.  **URL Redirection:** Accessing a generated short URL in a browser redirects the user to the original long URL.
13 |     -   *Why:* The fundamental purpose of the shortened link.
14 |     *   *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.
15 | 4.  **Basic Persistence:** Short URL mappings (short code -> long URL) persist across requests.
16 |     -   *Why:* Short URLs need to remain functional after creation.
17 |     *   *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.
18 | 
19 | # User Experience
20 | -   **User Persona:** Anyone wanting to shorten a long web link.
21 | -   **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.
22 | -   **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!").
23 | </context>
24 | <PRD>
25 | # Technical Architecture
26 | -   **System Components:**
27 |     -   Frontend: Single Page Application (SPA) built with Vite + React.
28 |     -   Backend: Simple API server (e.g., Node.js with Express).
29 | -   **Data Model:** A key-value store mapping `shortCode` (string) to `longUrl` (string).
30 | -   **APIs & Integrations:**
31 |     -   Backend API:
32 |         -   `POST /api/shorten`: Accepts `{ longUrl: string }` in the request body. Generates a unique `shortCode`, stores the mapping, returns `{ shortUrl: string }`.
33 |         -   `GET /:shortCode`: Looks up `shortCode`. If found, performs HTTP redirect to `longUrl`. If not found, returns 404.
34 | -   **Infrastructure:** Frontend can be hosted on static hosting. Backend needs a simple server environment (Node.js).
35 | -   **Libraries:**
36 |     -   Frontend: `react`, `react-dom`, `axios` (or `fetch` API) for API calls. Consider a simple state management solution if needed (e.g., `useState`, `useContext`).
37 |     -   Backend: `express`, `nanoid` (or similar for short code generation).
38 | 
39 | # Development Roadmap
40 | -   **MVP Requirements:**
41 |     1.  Setup Vite + React project.
42 |     2.  Create basic React UI components (InputForm, ResultDisplay).
43 |     3.  Setup basic Node.js/Express backend server.
44 |     4.  Implement backend data storage module (start with in-memory object).
45 |     5.  Implement unique short code generation logic (e.g., using `nanoid`).
46 |     6.  Implement backend `POST /api/shorten` endpoint logic.
47 |     7.  Implement backend `GET /:shortCode` redirect logic.
48 |     8.  Implement frontend logic to take input, call `POST /api/shorten`, and display the result.
49 |     9.  Basic frontend input validation (check if likely a URL).
50 | -   **Future Enhancements:** User accounts, custom short codes, analytics (click tracking), using a persistent database, error handling improvements, UI styling. (Out of scope for MVP).
51 | 
52 | # Logical Dependency Chain
53 | 1.  Vite + React Project Setup.
54 | 2.  Basic Backend Server Setup (Express).
55 | 3.  Backend Storage Module (in-memory first).
56 | 4.  Short Code Generation Logic.
57 | 5.  Implement `POST /api/shorten` endpoint (depends on 3 & 4).
58 | 6.  Implement `GET /:shortCode` endpoint (depends on 3).
59 | 7.  Frontend UI Components.
60 | 8.  Frontend logic to call `POST /api/shorten` (depends on 5 & 7).
61 | 9.  Frontend display logic (depends on 7 & 8).
62 |     *Goal is to get the backend API working first, then build the frontend to consume it.*
63 | 
64 | # Risks and Mitigations
65 | -   **Risk:** Short code collisions (generating the same code twice).
66 |     -   **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).
67 | -   **Risk:** Storing invalid or malicious URLs.
68 |     -   **Mitigation (MVP):** Basic URL validation on the frontend (simple regex) and potentially on the backend. Sanitize input. Advanced checks are out of scope.
69 | -   **Risk:** Scalability of in-memory store.
70 |     -   **Mitigation (MVP):** Acceptable for MVP. Acknowledge need for persistent database (JSON file, Redis, SQL/NoSQL DB) for future enhancement.
71 | 
72 | # Appendix
73 | -   Example Data Store (in-memory object):
74 |     ```javascript
75 |     // backend/storage.js
76 |     const urlMap = {
77 |       'aB3cD': 'https://very-long-url-example.com/with/path/and/query?params=true',
78 |       'xY7zW': 'https://another-example.org/'
79 |     };
80 |     // ... functions to get/set URLs ...
81 |     ```
82 | </PRD>
```

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

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

--------------------------------------------------------------------------------
/.claude/agents/task-checker.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | name: task-checker
  3 | 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>
  4 | model: sonnet
  5 | color: yellow
  6 | ---
  7 | 
  8 | 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'.
  9 | 
 10 | ## Core Responsibilities
 11 | 
 12 | 1. **Task Specification Review**
 13 |    - Retrieve task details using MCP tool `mcp__task-master-ai__get_task`
 14 |    - Understand the requirements, test strategy, and success criteria
 15 |    - Review any subtasks and their individual requirements
 16 | 
 17 | 2. **Implementation Verification**
 18 |    - Use `Read` tool to examine all created/modified files
 19 |    - Use `Bash` tool to run compilation and build commands
 20 |    - Use `Grep` tool to search for required patterns and implementations
 21 |    - Verify file structure matches specifications
 22 |    - Check that all required methods/functions are implemented
 23 | 
 24 | 3. **Test Execution**
 25 |    - Run tests specified in the task's testStrategy
 26 |    - Execute build commands (npm run build, tsc --noEmit, etc.)
 27 |    - Verify no compilation errors or warnings
 28 |    - Check for runtime errors where applicable
 29 |    - Test edge cases mentioned in requirements
 30 | 
 31 | 4. **Code Quality Assessment**
 32 |    - Verify code follows project conventions
 33 |    - Check for proper error handling
 34 |    - Ensure TypeScript typing is strict (no 'any' unless justified)
 35 |    - Verify documentation/comments where required
 36 |    - Check for security best practices
 37 | 
 38 | 5. **Dependency Validation**
 39 |    - Verify all task dependencies were actually completed
 40 |    - Check integration points with dependent tasks
 41 |    - Ensure no breaking changes to existing functionality
 42 | 
 43 | ## Verification Workflow
 44 | 
 45 | 1. **Retrieve Task Information**
 46 |    ```
 47 |    Use mcp__task-master-ai__get_task to get full task details
 48 |    Note the implementation requirements and test strategy
 49 |    ```
 50 | 
 51 | 2. **Check File Existence**
 52 |    ```bash
 53 |    # Verify all required files exist
 54 |    ls -la [expected directories]
 55 |    # Read key files to verify content
 56 |    ```
 57 | 
 58 | 3. **Verify Implementation**
 59 |    - Read each created/modified file
 60 |    - Check against requirements checklist
 61 |    - Verify all subtasks are complete
 62 | 
 63 | 4. **Run Tests**
 64 |    ```bash
 65 |    # TypeScript compilation
 66 |    cd [project directory] && npx tsc --noEmit
 67 |    
 68 |    # Run specified tests
 69 |    npm test [specific test files]
 70 |    
 71 |    # Build verification
 72 |    npm run build
 73 |    ```
 74 | 
 75 | 5. **Generate Verification Report**
 76 | 
 77 | ## Output Format
 78 | 
 79 | ```yaml
 80 | verification_report:
 81 |   task_id: [ID]
 82 |   status: PASS | FAIL | PARTIAL
 83 |   score: [1-10]
 84 |   
 85 |   requirements_met:
 86 |     - ✅ [Requirement that was satisfied]
 87 |     - ✅ [Another satisfied requirement]
 88 |     
 89 |   issues_found:
 90 |     - ❌ [Issue description]
 91 |     - ⚠️  [Warning or minor issue]
 92 |     
 93 |   files_verified:
 94 |     - path: [file path]
 95 |       status: [created/modified/verified]
 96 |       issues: [any problems found]
 97 |       
 98 |   tests_run:
 99 |     - command: [test command]
100 |       result: [pass/fail]
101 |       output: [relevant output]
102 |       
103 |   recommendations:
104 |     - [Specific fix needed]
105 |     - [Improvement suggestion]
106 |     
107 |   verdict: |
108 |     [Clear statement on whether task should be marked 'done' or sent back to 'pending']
109 |     [If FAIL: Specific list of what must be fixed]
110 |     [If PASS: Confirmation that all requirements are met]
111 | ```
112 | 
113 | ## Decision Criteria
114 | 
115 | **Mark as PASS (ready for 'done'):**
116 | - All required files exist and contain expected content
117 | - All tests pass successfully
118 | - No compilation or build errors
119 | - All subtasks are complete
120 | - Core requirements are met
121 | - Code quality is acceptable
122 | 
123 | **Mark as PARTIAL (may proceed with warnings):**
124 | - Core functionality is implemented
125 | - Minor issues that don't block functionality
126 | - Missing nice-to-have features
127 | - Documentation could be improved
128 | - Tests pass but coverage could be better
129 | 
130 | **Mark as FAIL (must return to 'pending'):**
131 | - Required files are missing
132 | - Compilation or build errors
133 | - Tests fail
134 | - Core requirements not met
135 | - Security vulnerabilities detected
136 | - Breaking changes to existing code
137 | 
138 | ## Important Guidelines
139 | 
140 | - **BE THOROUGH**: Check every requirement systematically
141 | - **BE SPECIFIC**: Provide exact file paths and line numbers for issues
142 | - **BE FAIR**: Distinguish between critical issues and minor improvements
143 | - **BE CONSTRUCTIVE**: Provide clear guidance on how to fix issues
144 | - **BE EFFICIENT**: Focus on requirements, not perfection
145 | 
146 | ## Tools You MUST Use
147 | 
148 | - `Read`: Examine implementation files (READ-ONLY)
149 | - `Bash`: Run tests and verification commands
150 | - `Grep`: Search for patterns in code
151 | - `mcp__task-master-ai__get_task`: Get task details
152 | - **NEVER use Write/Edit** - you only verify, not fix
153 | 
154 | ## Integration with Workflow
155 | 
156 | You are the quality gate between 'review' and 'done' status:
157 | 1. Task-executor implements and marks as 'review'
158 | 2. You verify and report PASS/FAIL
159 | 3. Claude either marks as 'done' (PASS) or 'pending' (FAIL)
160 | 4. If FAIL, task-executor re-implements based on your report
161 | 
162 | Your verification ensures high quality and prevents accumulation of technical debt.
```

--------------------------------------------------------------------------------
/assets/claude/agents/task-checker.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | name: task-checker
  3 | 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>
  4 | model: sonnet
  5 | color: yellow
  6 | ---
  7 | 
  8 | 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'.
  9 | 
 10 | ## Core Responsibilities
 11 | 
 12 | 1. **Task Specification Review**
 13 |    - Retrieve task details using MCP tool `mcp__task-master-ai__get_task`
 14 |    - Understand the requirements, test strategy, and success criteria
 15 |    - Review any subtasks and their individual requirements
 16 | 
 17 | 2. **Implementation Verification**
 18 |    - Use `Read` tool to examine all created/modified files
 19 |    - Use `Bash` tool to run compilation and build commands
 20 |    - Use `Grep` tool to search for required patterns and implementations
 21 |    - Verify file structure matches specifications
 22 |    - Check that all required methods/functions are implemented
 23 | 
 24 | 3. **Test Execution**
 25 |    - Run tests specified in the task's testStrategy
 26 |    - Execute build commands (npm run build, tsc --noEmit, etc.)
 27 |    - Verify no compilation errors or warnings
 28 |    - Check for runtime errors where applicable
 29 |    - Test edge cases mentioned in requirements
 30 | 
 31 | 4. **Code Quality Assessment**
 32 |    - Verify code follows project conventions
 33 |    - Check for proper error handling
 34 |    - Ensure TypeScript typing is strict (no 'any' unless justified)
 35 |    - Verify documentation/comments where required
 36 |    - Check for security best practices
 37 | 
 38 | 5. **Dependency Validation**
 39 |    - Verify all task dependencies were actually completed
 40 |    - Check integration points with dependent tasks
 41 |    - Ensure no breaking changes to existing functionality
 42 | 
 43 | ## Verification Workflow
 44 | 
 45 | 1. **Retrieve Task Information**
 46 |    ```
 47 |    Use mcp__task-master-ai__get_task to get full task details
 48 |    Note the implementation requirements and test strategy
 49 |    ```
 50 | 
 51 | 2. **Check File Existence**
 52 |    ```bash
 53 |    # Verify all required files exist
 54 |    ls -la [expected directories]
 55 |    # Read key files to verify content
 56 |    ```
 57 | 
 58 | 3. **Verify Implementation**
 59 |    - Read each created/modified file
 60 |    - Check against requirements checklist
 61 |    - Verify all subtasks are complete
 62 | 
 63 | 4. **Run Tests**
 64 |    ```bash
 65 |    # TypeScript compilation
 66 |    cd [project directory] && npx tsc --noEmit
 67 |    
 68 |    # Run specified tests
 69 |    npm test [specific test files]
 70 |    
 71 |    # Build verification
 72 |    npm run build
 73 |    ```
 74 | 
 75 | 5. **Generate Verification Report**
 76 | 
 77 | ## Output Format
 78 | 
 79 | ```yaml
 80 | verification_report:
 81 |   task_id: [ID]
 82 |   status: PASS | FAIL | PARTIAL
 83 |   score: [1-10]
 84 |   
 85 |   requirements_met:
 86 |     - ✅ [Requirement that was satisfied]
 87 |     - ✅ [Another satisfied requirement]
 88 |     
 89 |   issues_found:
 90 |     - ❌ [Issue description]
 91 |     - ⚠️  [Warning or minor issue]
 92 |     
 93 |   files_verified:
 94 |     - path: [file path]
 95 |       status: [created/modified/verified]
 96 |       issues: [any problems found]
 97 |       
 98 |   tests_run:
 99 |     - command: [test command]
100 |       result: [pass/fail]
101 |       output: [relevant output]
102 |       
103 |   recommendations:
104 |     - [Specific fix needed]
105 |     - [Improvement suggestion]
106 |     
107 |   verdict: |
108 |     [Clear statement on whether task should be marked 'done' or sent back to 'pending']
109 |     [If FAIL: Specific list of what must be fixed]
110 |     [If PASS: Confirmation that all requirements are met]
111 | ```
112 | 
113 | ## Decision Criteria
114 | 
115 | **Mark as PASS (ready for 'done'):**
116 | - All required files exist and contain expected content
117 | - All tests pass successfully
118 | - No compilation or build errors
119 | - All subtasks are complete
120 | - Core requirements are met
121 | - Code quality is acceptable
122 | 
123 | **Mark as PARTIAL (may proceed with warnings):**
124 | - Core functionality is implemented
125 | - Minor issues that don't block functionality
126 | - Missing nice-to-have features
127 | - Documentation could be improved
128 | - Tests pass but coverage could be better
129 | 
130 | **Mark as FAIL (must return to 'pending'):**
131 | - Required files are missing
132 | - Compilation or build errors
133 | - Tests fail
134 | - Core requirements not met
135 | - Security vulnerabilities detected
136 | - Breaking changes to existing code
137 | 
138 | ## Important Guidelines
139 | 
140 | - **BE THOROUGH**: Check every requirement systematically
141 | - **BE SPECIFIC**: Provide exact file paths and line numbers for issues
142 | - **BE FAIR**: Distinguish between critical issues and minor improvements
143 | - **BE CONSTRUCTIVE**: Provide clear guidance on how to fix issues
144 | - **BE EFFICIENT**: Focus on requirements, not perfection
145 | 
146 | ## Tools You MUST Use
147 | 
148 | - `Read`: Examine implementation files (READ-ONLY)
149 | - `Bash`: Run tests and verification commands
150 | - `Grep`: Search for patterns in code
151 | - `mcp__task-master-ai__get_task`: Get task details
152 | - **NEVER use Write/Edit** - you only verify, not fix
153 | 
154 | ## Integration with Workflow
155 | 
156 | You are the quality gate between 'review' and 'done' status:
157 | 1. Task-executor implements and marks as 'review'
158 | 2. You verify and report PASS/FAIL
159 | 3. Claude either marks as 'done' (PASS) or 'pending' (FAIL)
160 | 4. If FAIL, task-executor re-implements based on your report
161 | 
162 | Your verification ensures high quality and prevents accumulation of technical debt.
```

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

```markdown
  1 | ---
  2 | title: CLI Commands
  3 | sidebarTitle: "CLI Commands"
  4 | ---
  5 | 
  6 | 
  7 | <AccordionGroup>
  8 |   <Accordion title="Parse PRD">
  9 |     ```bash
 10 |     # Parse a PRD file and generate tasks
 11 |     task-master parse-prd <prd-file.txt>
 12 | 
 13 |     # Limit the number of tasks generated
 14 |     task-master parse-prd <prd-file.txt> --num-tasks=10
 15 |     ```
 16 |   </Accordion>
 17 | 
 18 |   <Accordion title="List Tasks">
 19 |     ```bash
 20 |     # List all tasks
 21 |     task-master list
 22 | 
 23 |     # List tasks with a specific status
 24 |     task-master list --status=<status>
 25 | 
 26 |     # List tasks with subtasks
 27 |     task-master list --with-subtasks
 28 | 
 29 |     # List tasks with a specific status and include subtasks
 30 |     task-master list --status=<status> --with-subtasks
 31 |     ```
 32 |   </Accordion>
 33 | 
 34 |   <Accordion title="Show Next Task">
 35 |     ```bash
 36 |     # Show the next task to work on based on dependencies and status
 37 |     task-master next
 38 |     ```
 39 |   </Accordion>
 40 | 
 41 |   <Accordion title="Show Specific Task">
 42 |     ```bash
 43 |     # Show details of a specific task
 44 |     task-master show <id>
 45 |     # or
 46 |     task-master show --id=<id>
 47 | 
 48 |     # View a specific subtask (e.g., subtask 2 of task 1)
 49 |     task-master show 1.2
 50 |     ```
 51 |   </Accordion>
 52 | 
 53 |   <Accordion title="Update Tasks">
 54 |     ```bash
 55 |     # Update tasks from a specific ID and provide context
 56 |     task-master update --from=<id> --prompt="<prompt>"
 57 |     ```
 58 |   </Accordion>
 59 | 
 60 |   <Accordion title="Update a Specific Task">
 61 |     ```bash
 62 |     # Update a single task by ID with new information
 63 |     task-master update-task --id=<id> --prompt="<prompt>"
 64 | 
 65 |     # Use research-backed updates with Perplexity AI
 66 |     task-master update-task --id=<id> --prompt="<prompt>" --research
 67 |     ```
 68 |   </Accordion>
 69 | 
 70 |   <Accordion title="Update a Subtask">
 71 |     ```bash
 72 |     # Append additional information to a specific subtask
 73 |     task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>"
 74 | 
 75 |     # Example: Add details about API rate limiting to subtask 2 of task 5
 76 |     task-master update-subtask --id=5.2 --prompt="Add rate limiting of 100 requests per minute"
 77 | 
 78 |     # Use research-backed updates with Perplexity AI
 79 |     task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>" --research
 80 |     ```
 81 | 
 82 |     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.
 83 |   </Accordion>
 84 | 
 85 |   <Accordion title="Generate Task Files">
 86 |     ```bash
 87 |     # Generate individual task files from tasks.json
 88 |     task-master generate
 89 |     ```
 90 |   </Accordion>
 91 | 
 92 |   <Accordion title="Set Task Status">
 93 |     ```bash
 94 |     # Set status of a single task
 95 |     task-master set-status --id=<id> --status=<status>
 96 | 
 97 |     # Set status for multiple tasks
 98 |     task-master set-status --id=1,2,3 --status=<status>
 99 | 
100 |     # Set status for subtasks
101 |     task-master set-status --id=1.1,1.2 --status=<status>
102 |     ```
103 | 
104 |     When marking a task as "done", all of its subtasks will automatically be marked as "done" as well.
105 |   </Accordion>
106 | 
107 |   <Accordion title="Expand Tasks">
108 |     ```bash
109 |     # Expand a specific task with subtasks
110 |     task-master expand --id=<id> --num=<number>
111 | 
112 |     # Expand with additional context
113 |     task-master expand --id=<id> --prompt="<context>"
114 | 
115 |     # Expand all pending tasks
116 |     task-master expand --all
117 | 
118 |     # Force regeneration of subtasks for tasks that already have them
119 |     task-master expand --all --force
120 | 
121 |     # Research-backed subtask generation for a specific task
122 |     task-master expand --id=<id> --research
123 | 
124 |     # Research-backed generation for all tasks
125 |     task-master expand --all --research
126 |     ```
127 |   </Accordion>
128 | 
129 |   <Accordion title="Clear Subtasks">
130 |     ```bash
131 |     # Clear subtasks from a specific task
132 |     task-master clear-subtasks --id=<id>
133 | 
134 |     # Clear subtasks from multiple tasks
135 |     task-master clear-subtasks --id=1,2,3
136 | 
137 |     # Clear subtasks from all tasks
138 |     task-master clear-subtasks --all
139 |     ```
140 |   </Accordion>
141 | 
142 |   <Accordion title="Analyze Task Complexity">
143 |     ```bash
144 |     # Analyze complexity of all tasks
145 |     task-master analyze-complexity
146 | 
147 |     # Save report to a custom location
148 |     task-master analyze-complexity --output=my-report.json
149 | 
150 |     # Use a specific LLM model
151 |     task-master analyze-complexity --model=claude-3-opus-20240229
152 | 
153 |     # Set a custom complexity threshold (1-10)
154 |     task-master analyze-complexity --threshold=6
155 | 
156 |     # Use an alternative tasks file
157 |     task-master analyze-complexity --file=custom-tasks.json
158 | 
159 |     # Use Perplexity AI for research-backed complexity analysis
160 |     task-master analyze-complexity --research
161 |     ```
162 |   </Accordion>
163 | 
164 |   <Accordion title="View Complexity Report">
165 |     ```bash
166 |     # Display the task complexity analysis report
167 |     task-master complexity-report
168 | 
169 |     # View a report at a custom location
170 |     task-master complexity-report --file=my-report.json
171 |     ```
172 |   </Accordion>
173 | 
174 |   <Accordion title="Managing Task Dependencies">
175 |     ```bash
176 |     # Add a dependency to a task
177 |     task-master add-dependency --id=<id> --depends-on=<id>
178 | 
179 |     # Remove a dependency from a task
180 |     task-master remove-dependency --id=<id> --depends-on=<id>
181 | 
182 |     # Validate dependencies without fixing them
183 |     task-master validate-dependencies
184 | 
185 |     # Find and fix invalid dependencies automatically
186 |     task-master fix-dependencies
187 |     ```
188 |   </Accordion>
189 | 
190 |   <Accordion title="Add a New Task">
191 |     ```bash
192 |     # Add a new task using AI
193 |     task-master add-task --prompt="Description of the new task"
194 | 
195 |     # Add a task with dependencies
196 |     task-master add-task --prompt="Description" --dependencies=1,2,3
197 | 
198 |     # Add a task with priority
199 |     task-master add-task --prompt="Description" --priority=high
200 |     ```
201 |   </Accordion>
202 | 
203 |   <Accordion title="Initialize a Project">
204 |     ```bash
205 |     # Initialize a new project with Task Master structure
206 |     task-master init
207 |     ```
208 |   </Accordion>
209 | </AccordionGroup>
210 | 
```

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

```javascript
  1 | /**
  2 |  * Unit tests for indicators module (priority and complexity indicators)
  3 |  */
  4 | import { jest } from '@jest/globals';
  5 | 
  6 | // Mock chalk using unstable_mockModule for ESM compatibility
  7 | jest.unstable_mockModule('chalk', () => ({
  8 | 	default: {
  9 | 		red: jest.fn((str) => str),
 10 | 		yellow: jest.fn((str) => str),
 11 | 		green: jest.fn((str) => str),
 12 | 		white: jest.fn((str) => str),
 13 | 		hex: jest.fn(() => jest.fn((str) => str))
 14 | 	}
 15 | }));
 16 | 
 17 | // Import after mocking
 18 | const {
 19 | 	getMcpPriorityIndicators,
 20 | 	getCliPriorityIndicators,
 21 | 	getPriorityIndicators,
 22 | 	getPriorityIndicator,
 23 | 	getStatusBarPriorityIndicators,
 24 | 	getPriorityColors,
 25 | 	getCliComplexityIndicators,
 26 | 	getStatusBarComplexityIndicators,
 27 | 	getComplexityColors,
 28 | 	getComplexityIndicator
 29 | } = await import('../../../src/ui/indicators.js');
 30 | 
 31 | describe('Priority Indicators', () => {
 32 | 	describe('getMcpPriorityIndicators', () => {
 33 | 		it('should return emoji indicators for MCP context', () => {
 34 | 			const indicators = getMcpPriorityIndicators();
 35 | 			expect(indicators).toEqual({
 36 | 				high: '🔴',
 37 | 				medium: '🟠',
 38 | 				low: '🟢'
 39 | 			});
 40 | 		});
 41 | 	});
 42 | 
 43 | 	describe('getCliPriorityIndicators', () => {
 44 | 		it('should return colored dot indicators for CLI context', () => {
 45 | 			const indicators = getCliPriorityIndicators();
 46 | 			expect(indicators).toHaveProperty('high');
 47 | 			expect(indicators).toHaveProperty('medium');
 48 | 			expect(indicators).toHaveProperty('low');
 49 | 			// Since chalk is mocked, we're just verifying structure
 50 | 			expect(indicators.high).toContain('●');
 51 | 		});
 52 | 	});
 53 | 
 54 | 	describe('getPriorityIndicators', () => {
 55 | 		it('should return MCP indicators when isMcp is true', () => {
 56 | 			const indicators = getPriorityIndicators(true);
 57 | 			expect(indicators).toEqual({
 58 | 				high: '🔴',
 59 | 				medium: '🟠',
 60 | 				low: '🟢'
 61 | 			});
 62 | 		});
 63 | 
 64 | 		it('should return CLI indicators when isMcp is false', () => {
 65 | 			const indicators = getPriorityIndicators(false);
 66 | 			expect(indicators).toHaveProperty('high');
 67 | 			expect(indicators).toHaveProperty('medium');
 68 | 			expect(indicators).toHaveProperty('low');
 69 | 		});
 70 | 
 71 | 		it('should default to CLI indicators when no parameter provided', () => {
 72 | 			const indicators = getPriorityIndicators();
 73 | 			expect(indicators).toHaveProperty('high');
 74 | 			expect(indicators.high).toContain('●');
 75 | 		});
 76 | 	});
 77 | 
 78 | 	describe('getPriorityIndicator', () => {
 79 | 		it('should return correct MCP indicator for valid priority', () => {
 80 | 			expect(getPriorityIndicator('high', true)).toBe('🔴');
 81 | 			expect(getPriorityIndicator('medium', true)).toBe('🟠');
 82 | 			expect(getPriorityIndicator('low', true)).toBe('🟢');
 83 | 		});
 84 | 
 85 | 		it('should return correct CLI indicator for valid priority', () => {
 86 | 			const highIndicator = getPriorityIndicator('high', false);
 87 | 			const mediumIndicator = getPriorityIndicator('medium', false);
 88 | 			const lowIndicator = getPriorityIndicator('low', false);
 89 | 
 90 | 			expect(highIndicator).toContain('●');
 91 | 			expect(mediumIndicator).toContain('●');
 92 | 			expect(lowIndicator).toContain('●');
 93 | 		});
 94 | 
 95 | 		it('should return medium indicator for invalid priority', () => {
 96 | 			expect(getPriorityIndicator('invalid', true)).toBe('🟠');
 97 | 			expect(getPriorityIndicator(null, true)).toBe('🟠');
 98 | 			expect(getPriorityIndicator(undefined, true)).toBe('🟠');
 99 | 		});
100 | 
101 | 		it('should default to CLI context when isMcp not provided', () => {
102 | 			const indicator = getPriorityIndicator('high');
103 | 			expect(indicator).toContain('●');
104 | 		});
105 | 	});
106 | });
107 | 
108 | describe('Complexity Indicators', () => {
109 | 	describe('getCliComplexityIndicators', () => {
110 | 		it('should return colored dot indicators for complexity levels', () => {
111 | 			const indicators = getCliComplexityIndicators();
112 | 			expect(indicators).toHaveProperty('high');
113 | 			expect(indicators).toHaveProperty('medium');
114 | 			expect(indicators).toHaveProperty('low');
115 | 			expect(indicators.high).toContain('●');
116 | 		});
117 | 	});
118 | 
119 | 	describe('getStatusBarComplexityIndicators', () => {
120 | 		it('should return single character indicators for status bars', () => {
121 | 			const indicators = getStatusBarComplexityIndicators();
122 | 			// Since chalk is mocked, we need to check for the actual characters
123 | 			expect(indicators.high).toContain('⋮');
124 | 			expect(indicators.medium).toContain(':');
125 | 			expect(indicators.low).toContain('.');
126 | 		});
127 | 	});
128 | 
129 | 	describe('getComplexityColors', () => {
130 | 		it('should return complexity color functions', () => {
131 | 			const colors = getComplexityColors();
132 | 			expect(colors).toHaveProperty('high');
133 | 			expect(colors).toHaveProperty('medium');
134 | 			expect(colors).toHaveProperty('low');
135 | 			// Verify they are functions (mocked chalk functions)
136 | 			expect(typeof colors.high).toBe('function');
137 | 		});
138 | 	});
139 | 
140 | 	describe('getComplexityIndicator', () => {
141 | 		it('should return high indicator for scores >= 7', () => {
142 | 			const cliIndicators = getCliComplexityIndicators();
143 | 			expect(getComplexityIndicator(7)).toBe(cliIndicators.high);
144 | 			expect(getComplexityIndicator(8)).toBe(cliIndicators.high);
145 | 			expect(getComplexityIndicator(10)).toBe(cliIndicators.high);
146 | 		});
147 | 
148 | 		it('should return low indicator for scores <= 3', () => {
149 | 			const cliIndicators = getCliComplexityIndicators();
150 | 			expect(getComplexityIndicator(1)).toBe(cliIndicators.low);
151 | 			expect(getComplexityIndicator(2)).toBe(cliIndicators.low);
152 | 			expect(getComplexityIndicator(3)).toBe(cliIndicators.low);
153 | 		});
154 | 
155 | 		it('should return medium indicator for scores 4-6', () => {
156 | 			const cliIndicators = getCliComplexityIndicators();
157 | 			expect(getComplexityIndicator(4)).toBe(cliIndicators.medium);
158 | 			expect(getComplexityIndicator(5)).toBe(cliIndicators.medium);
159 | 			expect(getComplexityIndicator(6)).toBe(cliIndicators.medium);
160 | 		});
161 | 
162 | 		it('should return status bar indicators when statusBar is true', () => {
163 | 			const statusBarIndicators = getStatusBarComplexityIndicators();
164 | 			expect(getComplexityIndicator(8, true)).toBe(statusBarIndicators.high);
165 | 			expect(getComplexityIndicator(5, true)).toBe(statusBarIndicators.medium);
166 | 			expect(getComplexityIndicator(2, true)).toBe(statusBarIndicators.low);
167 | 		});
168 | 	});
169 | });
170 | 
```

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

```typescript
  1 | /**
  2 |  * Cache Manager
  3 |  * Handles all caching logic with LRU eviction and analytics
  4 |  */
  5 | 
  6 | import type { ExtensionLogger } from '../../logger';
  7 | import type { CacheAnalytics, CacheConfig, CacheEntry } from '../types';
  8 | 
  9 | export class CacheManager {
 10 | 	private cache = new Map<string, CacheEntry>();
 11 | 	private analytics: CacheAnalytics = {
 12 | 		hits: 0,
 13 | 		misses: 0,
 14 | 		evictions: 0,
 15 | 		refreshes: 0,
 16 | 		totalSize: 0,
 17 | 		averageAccessTime: 0,
 18 | 		hitRate: 0
 19 | 	};
 20 | 	private backgroundRefreshTimer?: NodeJS.Timeout;
 21 | 
 22 | 	constructor(
 23 | 		private config: CacheConfig & { cacheDuration: number },
 24 | 		private logger: ExtensionLogger
 25 | 	) {
 26 | 		if (config.enableBackgroundRefresh) {
 27 | 			this.initializeBackgroundRefresh();
 28 | 		}
 29 | 	}
 30 | 
 31 | 	/**
 32 | 	 * Get data from cache if not expired
 33 | 	 */
 34 | 	get(key: string): any {
 35 | 		const startTime = Date.now();
 36 | 		const cached = this.cache.get(key);
 37 | 
 38 | 		if (cached) {
 39 | 			const isExpired =
 40 | 				Date.now() - cached.timestamp >=
 41 | 				(cached.ttl || this.config.cacheDuration);
 42 | 
 43 | 			if (!isExpired) {
 44 | 				// Update access statistics
 45 | 				cached.accessCount++;
 46 | 				cached.lastAccessed = Date.now();
 47 | 
 48 | 				if (this.config.enableAnalytics) {
 49 | 					this.analytics.hits++;
 50 | 				}
 51 | 
 52 | 				const accessTime = Date.now() - startTime;
 53 | 				this.logger.debug(
 54 | 					`Cache hit for ${key} (${accessTime}ms, ${cached.accessCount} accesses)`
 55 | 				);
 56 | 				return cached.data;
 57 | 			} else {
 58 | 				// Remove expired entry
 59 | 				this.cache.delete(key);
 60 | 				this.logger.debug(`Cache entry expired and removed: ${key}`);
 61 | 			}
 62 | 		}
 63 | 
 64 | 		if (this.config.enableAnalytics) {
 65 | 			this.analytics.misses++;
 66 | 		}
 67 | 
 68 | 		this.logger.debug(`Cache miss for ${key}`);
 69 | 		return null;
 70 | 	}
 71 | 
 72 | 	/**
 73 | 	 * Set data in cache with LRU eviction
 74 | 	 */
 75 | 	set(
 76 | 		key: string,
 77 | 		data: any,
 78 | 		options?: { ttl?: number; tags?: string[] }
 79 | 	): void {
 80 | 		const now = Date.now();
 81 | 		const dataSize = this.estimateDataSize(data);
 82 | 
 83 | 		// Create cache entry
 84 | 		const entry: CacheEntry = {
 85 | 			data,
 86 | 			timestamp: now,
 87 | 			accessCount: 1,
 88 | 			lastAccessed: now,
 89 | 			size: dataSize,
 90 | 			ttl: options?.ttl,
 91 | 			tags: options?.tags || [key.split('_')[0]]
 92 | 		};
 93 | 
 94 | 		// Check if we need to evict entries (LRU strategy)
 95 | 		if (this.cache.size >= this.config.maxSize) {
 96 | 			this.evictLRUEntries(Math.max(1, Math.floor(this.config.maxSize * 0.1)));
 97 | 		}
 98 | 
 99 | 		this.cache.set(key, entry);
100 | 		this.logger.debug(
101 | 			`Cached data for ${key} (size: ${dataSize} bytes, TTL: ${entry.ttl || this.config.cacheDuration}ms)`
102 | 		);
103 | 
104 | 		// Trigger prefetch if enabled
105 | 		if (this.config.enablePrefetch) {
106 | 			this.scheduleRelatedDataPrefetch(key, data);
107 | 		}
108 | 	}
109 | 
110 | 	/**
111 | 	 * Clear cache entries matching a pattern
112 | 	 */
113 | 	clearPattern(pattern: string): void {
114 | 		let evictedCount = 0;
115 | 		for (const key of this.cache.keys()) {
116 | 			if (key.includes(pattern)) {
117 | 				this.cache.delete(key);
118 | 				evictedCount++;
119 | 			}
120 | 		}
121 | 
122 | 		if (evictedCount > 0) {
123 | 			this.analytics.evictions += evictedCount;
124 | 			this.logger.debug(
125 | 				`Evicted ${evictedCount} cache entries matching pattern: ${pattern}`
126 | 			);
127 | 		}
128 | 	}
129 | 
130 | 	/**
131 | 	 * Clear all cached data
132 | 	 */
133 | 	clear(): void {
134 | 		this.cache.clear();
135 | 		this.resetAnalytics();
136 | 	}
137 | 
138 | 	/**
139 | 	 * Get cache analytics
140 | 	 */
141 | 	getAnalytics(): CacheAnalytics {
142 | 		this.updateAnalytics();
143 | 		return { ...this.analytics };
144 | 	}
145 | 
146 | 	/**
147 | 	 * Get frequently accessed entries for background refresh
148 | 	 */
149 | 	getRefreshCandidates(): Array<[string, CacheEntry]> {
150 | 		return Array.from(this.cache.entries())
151 | 			.filter(([key, entry]) => {
152 | 				const age = Date.now() - entry.timestamp;
153 | 				const isNearExpiration = age > this.config.cacheDuration * 0.7;
154 | 				const isFrequentlyAccessed = entry.accessCount >= 3;
155 | 				return (
156 | 					isNearExpiration && isFrequentlyAccessed && key.includes('get_tasks')
157 | 				);
158 | 			})
159 | 			.sort((a, b) => b[1].accessCount - a[1].accessCount)
160 | 			.slice(0, 5);
161 | 	}
162 | 
163 | 	/**
164 | 	 * Update refresh count for analytics
165 | 	 */
166 | 	incrementRefreshes(): void {
167 | 		this.analytics.refreshes++;
168 | 	}
169 | 
170 | 	/**
171 | 	 * Cleanup resources
172 | 	 */
173 | 	destroy(): void {
174 | 		if (this.backgroundRefreshTimer) {
175 | 			clearInterval(this.backgroundRefreshTimer);
176 | 			this.backgroundRefreshTimer = undefined;
177 | 		}
178 | 		this.clear();
179 | 	}
180 | 
181 | 	private initializeBackgroundRefresh(): void {
182 | 		if (this.backgroundRefreshTimer) {
183 | 			clearInterval(this.backgroundRefreshTimer);
184 | 		}
185 | 
186 | 		const interval = this.config.refreshInterval;
187 | 		this.backgroundRefreshTimer = setInterval(() => {
188 | 			// Background refresh is handled by the main API class
189 | 			// This just maintains the timer
190 | 		}, interval);
191 | 
192 | 		this.logger.debug(
193 | 			`Cache background refresh initialized with ${interval}ms interval`
194 | 		);
195 | 	}
196 | 
197 | 	private evictLRUEntries(count: number): void {
198 | 		const entries = Array.from(this.cache.entries())
199 | 			.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)
200 | 			.slice(0, count);
201 | 
202 | 		for (const [key] of entries) {
203 | 			this.cache.delete(key);
204 | 			this.analytics.evictions++;
205 | 		}
206 | 
207 | 		if (entries.length > 0) {
208 | 			this.logger.debug(`Evicted ${entries.length} LRU cache entries`);
209 | 		}
210 | 	}
211 | 
212 | 	private estimateDataSize(data: any): number {
213 | 		try {
214 | 			return JSON.stringify(data).length * 2; // Rough estimate
215 | 		} catch {
216 | 			return 1000; // Default fallback
217 | 		}
218 | 	}
219 | 
220 | 	private scheduleRelatedDataPrefetch(key: string, data: any): void {
221 | 		if (key.includes('get_tasks') && Array.isArray(data)) {
222 | 			this.logger.debug(
223 | 				`Scheduled prefetch for ${data.length} tasks related to ${key}`
224 | 			);
225 | 		}
226 | 	}
227 | 
228 | 	private resetAnalytics(): void {
229 | 		this.analytics = {
230 | 			hits: 0,
231 | 			misses: 0,
232 | 			evictions: 0,
233 | 			refreshes: 0,
234 | 			totalSize: 0,
235 | 			averageAccessTime: 0,
236 | 			hitRate: 0
237 | 		};
238 | 	}
239 | 
240 | 	private updateAnalytics(): void {
241 | 		const total = this.analytics.hits + this.analytics.misses;
242 | 		this.analytics.hitRate = total > 0 ? this.analytics.hits / total : 0;
243 | 		this.analytics.totalSize = this.cache.size;
244 | 
245 | 		if (this.cache.size > 0) {
246 | 			const totalAccessTime = Array.from(this.cache.values()).reduce(
247 | 				(sum, entry) => sum + (entry.lastAccessed - entry.timestamp),
248 | 				0
249 | 			);
250 | 			this.analytics.averageAccessTime = totalAccessTime / this.cache.size;
251 | 		}
252 | 	}
253 | }
254 | 
```

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

```markdown
  1 | # GetTaskList POC Status
  2 | 
  3 | ## ✅ What We've Accomplished
  4 | 
  5 | We've successfully implemented a complete end-to-end proof of concept for the `getTaskList` functionality with improved separation of concerns:
  6 | 
  7 | ### 1. Clean Architecture Layers with Proper Separation
  8 | 
  9 | #### Configuration Layer (ConfigManager)
 10 | - Single source of truth for configuration
 11 | - Manages active tag and storage settings
 12 | - Handles config.json persistence
 13 | - Determines storage type (file vs API)
 14 | 
 15 | #### Service Layer (TaskService)
 16 | - Core business logic and operations
 17 | - `getTaskList()` method that coordinates between ConfigManager and Storage
 18 | - Handles all filtering and task processing
 19 | - Manages storage lifecycle
 20 | 
 21 | #### Facade Layer (TaskMasterCore)
 22 | - Simplified API for consumers
 23 | - Delegates to TaskService for operations
 24 | - Backwards compatible `listTasks()` method
 25 | - New `getTaskList()` method (preferred naming)
 26 | 
 27 | #### Domain Layer (Entities)
 28 | - `TaskEntity` with business logic
 29 | - Validation and status transitions
 30 | - Dependency checking (`canComplete()`)
 31 | 
 32 | #### Infrastructure Layer (Storage)
 33 | - `IStorage` interface for abstraction
 34 | - `FileStorage` for local files (handles 'master' tag correctly)
 35 | - `ApiStorage` for Hamster integration
 36 | - `StorageFactory` for automatic selection
 37 | - **NO business logic** - only persistence
 38 | 
 39 | ### 2. Storage Abstraction Benefits
 40 | 
 41 | ```typescript
 42 | // Same API works with different backends
 43 | const fileCore = createTaskMasterCore(path, { 
 44 |   storage: { type: 'file' } 
 45 | });
 46 | 
 47 | const apiCore = createTaskMasterCore(path, { 
 48 |   storage: { 
 49 |     type: 'api',
 50 |     apiEndpoint: 'https://hamster.ai',
 51 |     apiAccessToken: 'xxx' 
 52 |   } 
 53 | });
 54 | 
 55 | // Identical usage
 56 | const result = await core.listTasks({ 
 57 |   filter: { status: 'pending' } 
 58 | });
 59 | ```
 60 | 
 61 | ### 3. Type Safety Throughout
 62 | 
 63 | - Full TypeScript implementation
 64 | - Comprehensive interfaces
 65 | - Type-safe filters and options
 66 | - Proper error types
 67 | 
 68 | ### 4. Testing Coverage
 69 | 
 70 | - 50 tests passing
 71 | - Unit tests for core components
 72 | - Integration tests for listTasks
 73 | - Mock implementations for testing
 74 | 
 75 | ## 📊 Architecture Validation
 76 | 
 77 | ### ✅ Separation of Concerns
 78 | - **CLI** handles UI/formatting only
 79 | - **tm-core** handles business logic
 80 | - **Storage** handles persistence
 81 | - Each layer is independently testable
 82 | 
 83 | ### ✅ Extensibility
 84 | - Easy to add new storage types (database, S3, etc.)
 85 | - New filters can be added to `TaskFilter`
 86 | - AI providers follow same pattern (BaseProvider)
 87 | 
 88 | ### ✅ Error Handling
 89 | - Consistent `TaskMasterError` with codes
 90 | - Context preservation
 91 | - User-friendly messages
 92 | 
 93 | ### ✅ Performance Considerations
 94 | - File locking for concurrent access
 95 | - Atomic writes with temp files
 96 | - Retry logic with exponential backoff
 97 | - Request timeout handling
 98 | 
 99 | ## 🔄 Integration Path
100 | 
101 | ### Current CLI Structure
102 | ```javascript
103 | // scripts/modules/task-manager/list-tasks.js
104 | listTasks(tasksPath, statusFilter, reportPath, withSubtasks, outputFormat, context)
105 | // Directly reads files, handles all logic
106 | ```
107 | 
108 | ### New Integration Structure
109 | ```javascript
110 | // Using tm-core with proper separation of concerns
111 | const tmCore = createTaskMasterCore(projectPath, config);
112 | const result = await tmCore.getTaskList(options);
113 | // CLI only handles formatting result for display
114 | 
115 | // Under the hood:
116 | // 1. ConfigManager determines active tag and storage type
117 | // 2. TaskService uses storage to fetch tasks for the tag
118 | // 3. TaskService applies business logic and filters
119 | // 4. Storage only handles reading/writing - no business logic
120 | ```
121 | 
122 | ## 📈 Metrics
123 | 
124 | ### Code Quality
125 | - **Clean Code**: Methods under 40 lines ✅
126 | - **Single Responsibility**: Each class has one purpose ✅
127 | - **DRY**: No code duplication ✅
128 | - **Type Coverage**: 100% TypeScript ✅
129 | 
130 | ### Test Coverage
131 | - **Unit Tests**: BaseProvider, TaskEntity ✅
132 | - **Integration Tests**: Full listTasks flow ✅
133 | - **Storage Tests**: File and API operations ✅
134 | 
135 | ## 🎯 POC Success Criteria
136 | 
137 | | Criteria | Status | Notes |
138 | |----------|--------|-------|
139 | | Clean architecture | ✅ | Clear layer separation |
140 | | Storage abstraction | ✅ | File + API storage working |
141 | | Type safety | ✅ | Full TypeScript |
142 | | Error handling | ✅ | Comprehensive error system |
143 | | Testing | ✅ | 50 tests passing |
144 | | Performance | ✅ | Optimized with caching, batching |
145 | | Documentation | ✅ | Architecture docs created |
146 | 
147 | ## 🚀 Next Steps
148 | 
149 | ### Immediate (Complete ListTasks Integration)
150 | 1. Create npm script to test integration example
151 | 2. Add mock Hamster API for testing
152 | 3. Create migration guide for CLI
153 | 
154 | ### Phase 1 Remaining Work
155 | Based on this POC success, implement remaining operations:
156 | - `addTask()` - Add new tasks
157 | - `updateTask()` - Update existing tasks  
158 | - `deleteTask()` - Remove tasks
159 | - `expandTask()` - Break into subtasks
160 | - Tag management operations
161 | 
162 | ### Phase 2 (AI Integration)
163 | - Complete AI provider implementations
164 | - Task generation from PRD
165 | - Task complexity analysis
166 | - Auto-expansion of tasks
167 | 
168 | ## 💡 Lessons Learned
169 | 
170 | ### What Worked Well
171 | 1. **Separation of Concerns** - ConfigManager, TaskService, and Storage have clear responsibilities
172 | 2. **Storage Factory Pattern** - Clean abstraction for multiple backends
173 | 3. **Entity Pattern** - Business logic encapsulation
174 | 4. **Template Method Pattern** - BaseProvider for AI providers
175 | 5. **Comprehensive Error Handling** - TaskMasterError with context
176 | 
177 | ### Improvements Made
178 | 1. Migrated from Jest to Vitest (faster)
179 | 2. Replaced ESLint/Prettier with Biome (unified tooling)
180 | 3. Fixed conflicting interface definitions
181 | 4. Added proper TypeScript exports
182 | 5. **Better Architecture** - Separated configuration, business logic, and persistence
183 | 6. **Proper Tag Handling** - 'master' tag maps correctly to tasks.json
184 | 7. **Clean Storage Layer** - Removed business logic from storage
185 | 
186 | ## ✨ Conclusion
187 | 
188 | The ListTasks POC successfully validates our architecture. The structure is:
189 | - **Clean and maintainable**
190 | - **Properly abstracted** 
191 | - **Well-tested**
192 | - **Ready for extension**
193 | 
194 | We can confidently proceed with implementing the remaining functionality following this same pattern.
```

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

```markdown
  1 | ---
  2 | title: "Task Master Commands"
  3 | description: "A comprehensive reference of all available Task Master commands"
  4 | ---
  5 | 
  6 | <AccordionGroup>
  7 |   <Accordion title="Parse PRD">
  8 |     ```bash
  9 |     # Parse a PRD file and generate tasks
 10 |     task-master parse-prd <prd-file.txt>
 11 | 
 12 |     # Limit the number of tasks generated
 13 |     task-master parse-prd <prd-file.txt> --num-tasks=10
 14 |     ```
 15 |   </Accordion>
 16 | 
 17 |   <Accordion title="List Tasks">
 18 |     ```bash
 19 |     # List all tasks
 20 |     task-master list
 21 | 
 22 |     # List tasks with a specific status
 23 |     task-master list --status=<status>
 24 | 
 25 |     # List tasks with subtasks
 26 |     task-master list --with-subtasks
 27 | 
 28 |     # List tasks with a specific status and include subtasks
 29 |     task-master list --status=<status> --with-subtasks
 30 |     ```
 31 |   </Accordion>
 32 | 
 33 |   <Accordion title="Show Next Task">
 34 |     ```bash
 35 |     # Show the next task to work on based on dependencies and status
 36 |     task-master next
 37 |     ```
 38 |   </Accordion>
 39 | 
 40 |   <Accordion title="Show Specific Task">
 41 |     ```bash
 42 |     # Show details of a specific task
 43 |     task-master show <id>
 44 |     # or
 45 |     task-master show --id=<id>
 46 | 
 47 |     # View a specific subtask (e.g., subtask 2 of task 1)
 48 |     task-master show 1.2
 49 |     ```
 50 |   </Accordion>
 51 | 
 52 |   <Accordion title="Update Tasks">
 53 |     ```bash
 54 |     # Update tasks from a specific ID and provide context
 55 |     task-master update --from=<id> --prompt="<prompt>"
 56 |     ```
 57 |   </Accordion>
 58 | 
 59 |   <Accordion title="Update a Specific Task">
 60 |     ```bash
 61 |     # Update a single task by ID with new information
 62 |     task-master update-task --id=<id> --prompt="<prompt>"
 63 | 
 64 |     # Use research-backed updates with Perplexity AI
 65 |     task-master update-task --id=<id> --prompt="<prompt>" --research
 66 |     ```
 67 |   </Accordion>
 68 | 
 69 |   <Accordion title="Update a Subtask">
 70 |     ```bash
 71 |     # Append additional information to a specific subtask
 72 |     task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>"
 73 | 
 74 |     # Example: Add details about API rate limiting to subtask 2 of task 5
 75 |     task-master update-subtask --id=5.2 --prompt="Add rate limiting of 100 requests per minute"
 76 | 
 77 |     # Use research-backed updates with Perplexity AI
 78 |     task-master update-subtask --id=<parentId.subtaskId> --prompt="<prompt>" --research
 79 |     ```
 80 | 
 81 |     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.
 82 |   </Accordion>
 83 | 
 84 |   <Accordion title="Generate Task Files">
 85 |     ```bash
 86 |     # Generate individual task files from tasks.json
 87 |     task-master generate
 88 |     ```
 89 |   </Accordion>
 90 | 
 91 |   <Accordion title="Set Task Status">
 92 |     ```bash
 93 |     # Set status of a single task
 94 |     task-master set-status --id=<id> --status=<status>
 95 | 
 96 |     # Set status for multiple tasks
 97 |     task-master set-status --id=1,2,3 --status=<status>
 98 | 
 99 |     # Set status for subtasks
100 |     task-master set-status --id=1.1,1.2 --status=<status>
101 |     ```
102 | 
103 |     When marking a task as "done", all of its subtasks will automatically be marked as "done" as well.
104 |   </Accordion>
105 | 
106 |   <Accordion title="Expand Tasks">
107 |     ```bash
108 |     # Expand a specific task with subtasks
109 |     task-master expand --id=<id> --num=<number>
110 | 
111 |     # Expand with additional context
112 |     task-master expand --id=<id> --prompt="<context>"
113 | 
114 |     # Expand all pending tasks
115 |     task-master expand --all
116 | 
117 |     # Force regeneration of subtasks for tasks that already have them
118 |     task-master expand --all --force
119 | 
120 |     # Research-backed subtask generation for a specific task
121 |     task-master expand --id=<id> --research
122 | 
123 |     # Research-backed generation for all tasks
124 |     task-master expand --all --research
125 |     ```
126 |   </Accordion>
127 | 
128 |   <Accordion title="Clear Subtasks">
129 |     ```bash
130 |     # Clear subtasks from a specific task
131 |     task-master clear-subtasks --id=<id>
132 | 
133 |     # Clear subtasks from multiple tasks
134 |     task-master clear-subtasks --id=1,2,3
135 | 
136 |     # Clear subtasks from all tasks
137 |     task-master clear-subtasks --all
138 |     ```
139 |   </Accordion>
140 | 
141 |   <Accordion title="Analyze Task Complexity">
142 |     ```bash
143 |     # Analyze complexity of all tasks
144 |     task-master analyze-complexity
145 | 
146 |     # Save report to a custom location
147 |     task-master analyze-complexity --output=my-report.json
148 | 
149 |     # Use a specific LLM model
150 |     task-master analyze-complexity --model=claude-3-opus-20240229
151 | 
152 |     # Set a custom complexity threshold (1-10)
153 |     task-master analyze-complexity --threshold=6
154 | 
155 |     # Use an alternative tasks file
156 |     task-master analyze-complexity --file=custom-tasks.json
157 | 
158 |     # Use Perplexity AI for research-backed complexity analysis
159 |     task-master analyze-complexity --research
160 |     ```
161 |   </Accordion>
162 | 
163 |   <Accordion title="View Complexity Report">
164 |     ```bash
165 |     # Display the task complexity analysis report
166 |     task-master complexity-report
167 | 
168 |     # View a report at a custom location
169 |     task-master complexity-report --file=my-report.json
170 |     ```
171 |   </Accordion>
172 | 
173 |   <Accordion title="Managing Task Dependencies">
174 |     ```bash
175 |     # Add a dependency to a task
176 |     task-master add-dependency --id=<id> --depends-on=<id>
177 | 
178 |     # Remove a dependency from a task
179 |     task-master remove-dependency --id=<id> --depends-on=<id>
180 | 
181 |     # Validate dependencies without fixing them
182 |     task-master validate-dependencies
183 | 
184 |     # Find and fix invalid dependencies automatically
185 |     task-master fix-dependencies
186 |     ```
187 |   </Accordion>
188 | 
189 |   <Accordion title="Add a New Task">
190 |     ```bash
191 |     # Add a new task using AI
192 |     task-master add-task --prompt="Description of the new task"
193 | 
194 |     # Add a task with dependencies
195 |     task-master add-task --prompt="Description" --dependencies=1,2,3
196 | 
197 |     # Add a task with priority
198 |     task-master add-task --prompt="Description" --priority=high
199 |     ```
200 |   </Accordion>
201 | 
202 |   <Accordion title="Initialize a Project">
203 |     ```bash
204 |     # Initialize a new project with Task Master structure
205 |     task-master init
206 |     ```
207 |   </Accordion>
208 | </AccordionGroup>
209 | 
```
Page 14/52FirstPrevNextLast