#
tokens: 49253/50000 34/821 files (page 8/38)
lines: off (toggle) GitHub
raw markdown copy
This is page 8 of 38. Use http://codebase.md/eyaltoledano/claude-task-master?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

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

```javascript
import { jest } from '@jest/globals';
import fs from 'fs';
import path from 'path';
import os from 'os';
import { execSync } from 'child_process';

describe('Roo Files Inclusion in Package', () => {
	// This test verifies that the required Roo files are included in the final package

	test('package.json includes dist/** in the "files" array for bundled files', () => {
		// Read the package.json file
		const packageJsonPath = path.join(process.cwd(), 'package.json');
		const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));

		// Check if dist/** is included in the files array (which contains bundled output including Roo files)
		expect(packageJson.files).toContain('dist/**');
	});

	test('roo.js profile contains logic for Roo directory creation and file copying', () => {
		// Read the roo.js profile file
		const rooJsPath = path.join(process.cwd(), 'src', 'profiles', 'roo.js');
		const rooJsContent = fs.readFileSync(rooJsPath, 'utf8');

		// Check for the main handler function
		expect(
			rooJsContent.includes('onAddRulesProfile(targetDir, assetsDir)')
		).toBe(true);

		// Check for general recursive copy of assets/roocode
		expect(
			rooJsContent.includes('copyRecursiveSync(sourceDir, targetDir)')
		).toBe(true);

		// Check for updated path handling
		expect(rooJsContent.includes("path.join(assetsDir, 'roocode')")).toBe(true);

		// Check for .roomodes file copying logic (source and destination paths)
		expect(rooJsContent.includes("path.join(sourceDir, '.roomodes')")).toBe(
			true
		);
		expect(rooJsContent.includes("path.join(targetDir, '.roomodes')")).toBe(
			true
		);

		// Check for mode-specific rule file copying logic
		expect(rooJsContent.includes('for (const mode of ROO_MODES)')).toBe(true);
		expect(
			rooJsContent.includes(
				'path.join(rooModesDir, `rules-${mode}`, `${mode}-rules`)'
			)
		).toBe(true);
		expect(
			rooJsContent.includes(
				"path.join(targetDir, '.roo', `rules-${mode}`, `${mode}-rules`)"
			)
		).toBe(true);

		// Check for import of ROO_MODES from profiles.js instead of local definition
		expect(
			rooJsContent.includes(
				"import { ROO_MODES } from '../constants/profiles.js'"
			)
		).toBe(true);

		// Verify ROO_MODES is used in the for loop
		expect(rooJsContent.includes('for (const mode of ROO_MODES)')).toBe(true);

		// Verify mode variable is used in the template strings (this confirms modes are being processed)
		expect(rooJsContent.includes('rules-${mode}')).toBe(true);
		expect(rooJsContent.includes('${mode}-rules')).toBe(true);

		// Verify that the ROO_MODES constant is properly imported and used
		// We should be able to find the template literals that use the mode variable
		expect(rooJsContent.includes('`rules-${mode}`')).toBe(true);
		expect(rooJsContent.includes('`${mode}-rules`')).toBe(true);
		expect(rooJsContent.includes('Copied ${mode}-rules to ${dest}')).toBe(true);

		// Also verify that the expected mode names are defined in the imported constant
		// by checking that the import is from the correct file that contains all 6 modes
		const profilesConstantsPath = path.join(
			process.cwd(),
			'src',
			'constants',
			'profiles.js'
		);
		const profilesContent = fs.readFileSync(profilesConstantsPath, 'utf8');

		// Check that ROO_MODES is exported and contains all expected modes
		expect(profilesContent.includes('export const ROO_MODES')).toBe(true);
		const expectedModes = [
			'architect',
			'ask',
			'orchestrator',
			'code',
			'debug',
			'test'
		];
		expectedModes.forEach((mode) => {
			expect(profilesContent.includes(`'${mode}'`)).toBe(true);
		});
	});

	test('source Roo files exist in assets directory', () => {
		// Verify that the source files for Roo integration exist
		expect(
			fs.existsSync(path.join(process.cwd(), 'assets', 'roocode', '.roo'))
		).toBe(true);
		expect(
			fs.existsSync(path.join(process.cwd(), 'assets', 'roocode', '.roomodes'))
		).toBe(true);
	});
});

```

--------------------------------------------------------------------------------
/apps/extension/src/services/terminal-manager.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Terminal Manager - Handles task execution in VS Code terminals
 * Uses @tm/core for consistent task management with the CLI
 */

import * as vscode from 'vscode';
import { createTaskMasterCore, type TaskMasterCore } from '@tm/core';
import type { ExtensionLogger } from '../utils/logger';

export interface TerminalExecutionOptions {
	taskId: string;
	taskTitle: string;
	tag?: string;
}

export interface TerminalExecutionResult {
	success: boolean;
	error?: string;
	terminalName?: string;
}

export class TerminalManager {
	private terminals = new Map<string, vscode.Terminal>();
	private tmCore?: TaskMasterCore;

	constructor(
		private context: vscode.ExtensionContext,
		private logger: ExtensionLogger
	) {}

	/**
	 * Execute a task in a new VS Code terminal with Claude
	 * Uses @tm/core for consistent task management with the CLI
	 */
	async executeTask(
		options: TerminalExecutionOptions
	): Promise<TerminalExecutionResult> {
		const { taskTitle, tag } = options;
		// Ensure taskId is always a string
		const taskId = String(options.taskId);

		this.logger.log(
			`Starting task execution for ${taskId}: ${taskTitle}${tag ? ` (tag: ${tag})` : ''}`
		);
		this.logger.log(`TaskId type: ${typeof taskId}, value: ${taskId}`);

		try {
			// Initialize tm-core if needed
			await this.initializeCore();

			// Use tm-core to start the task (same as CLI)
			const startResult = await this.tmCore!.startTask(taskId, {
				dryRun: false,
				force: false,
				updateStatus: true
			});

			if (!startResult.started || !startResult.executionOutput) {
				throw new Error(
					startResult.error || 'Failed to start task with tm-core'
				);
			}

			// Create terminal with custom TaskMaster icon
			const terminalName = `Task ${taskId}: ${taskTitle}`;
			const terminal = this.createTerminal(terminalName);

			// Store terminal reference for potential cleanup
			this.terminals.set(taskId, terminal);

			// Show terminal and run Claude command
			terminal.show();
			const command = `claude "${startResult.executionOutput}"`;
			terminal.sendText(command);

			this.logger.log(`Launched Claude for task ${taskId} using tm-core`);

			return {
				success: true,
				terminalName
			};
		} catch (error) {
			this.logger.error('Failed to execute task:', error);
			return {
				success: false,
				error: error instanceof Error ? error.message : 'Unknown error'
			};
		}
	}

	/**
	 * Create a new terminal with TaskMaster branding
	 */
	private createTerminal(name: string): vscode.Terminal {
		const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;

		return vscode.window.createTerminal({
			name,
			cwd: workspaceRoot,
			iconPath: new vscode.ThemeIcon('play') // Use a VS Code built-in icon for now
		});
	}

	/**
	 * Initialize TaskMaster Core (same as CLI)
	 */
	private async initializeCore(): Promise<void> {
		if (!this.tmCore) {
			const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
			if (!workspaceRoot) {
				throw new Error('No workspace folder found');
			}
			this.tmCore = await createTaskMasterCore({ projectPath: workspaceRoot });
		}
	}

	/**
	 * Get terminal by task ID (if still active)
	 */
	getTerminalByTaskId(taskId: string): vscode.Terminal | undefined {
		return this.terminals.get(taskId);
	}

	/**
	 * Clean up terminated terminals
	 */
	cleanupTerminal(taskId: string): void {
		const terminal = this.terminals.get(taskId);
		if (terminal) {
			this.terminals.delete(taskId);
		}
	}

	/**
	 * Dispose all managed terminals and clean up tm-core
	 */
	async dispose(): Promise<void> {
		this.terminals.forEach((terminal) => {
			try {
				terminal.dispose();
			} catch (error) {
				this.logger.error('Failed to dispose terminal:', error);
			}
		});
		this.terminals.clear();

		if (this.tmCore) {
			try {
				await this.tmCore.close();
				this.tmCore = undefined;
			} catch (error) {
				this.logger.error('Failed to close tm-core:', error);
			}
		}
	}
}

```

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

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

// --- Mock dependencies BEFORE module import ---
jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
	readJSON: jest.fn(),
	writeJSON: jest.fn(),
	log: jest.fn(),
	CONFIG: {
		model: 'mock-model',
		maxTokens: 4000,
		temperature: 0.7,
		debug: false
	},
	findTaskById: jest.fn(),
	truncate: jest.fn((t) => t),
	isSilentMode: jest.fn(() => false)
}));

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

// fs is used for file deletion side-effects – stub the methods we touch
jest.unstable_mockModule('fs', () => ({
	existsSync: jest.fn(() => true),
	unlinkSync: jest.fn()
}));

// path is fine to keep as real since only join/dirname used – no side effects

// Import mocked modules
const { readJSON, writeJSON, log } = await import(
	'../../../../../scripts/modules/utils.js'
);
const generateTaskFiles = (
	await import(
		'../../../../../scripts/modules/task-manager/generate-task-files.js'
	)
).default;
const fs = await import('fs');

// Import module under test (AFTER mocks in place)
const { default: removeTask } = await import(
	'../../../../../scripts/modules/task-manager/remove-task.js'
);

// ---- Test data helpers ----
const buildSampleTaggedTasks = () => ({
	master: {
		tasks: [
			{ id: 1, title: 'Task 1', status: 'pending', dependencies: [] },
			{ id: 2, title: 'Task 2', status: 'pending', dependencies: [1] },
			{
				id: 3,
				title: 'Parent',
				status: 'pending',
				dependencies: [],
				subtasks: [
					{ id: 1, title: 'Sub 3.1', status: 'pending', dependencies: [] }
				]
			}
		]
	},
	other: {
		tasks: [{ id: 99, title: 'Shadow', status: 'pending', dependencies: [1] }]
	}
});

// Utility to deep clone sample each test
const getFreshData = () => JSON.parse(JSON.stringify(buildSampleTaggedTasks()));

// ----- Tests -----

describe('removeTask', () => {
	beforeEach(() => {
		jest.clearAllMocks();
		// readJSON returns deep copy so each test isolated
		readJSON.mockImplementation(() => {
			return {
				...getFreshData().master,
				tag: 'master',
				_rawTaggedData: getFreshData()
			};
		});
		writeJSON.mockResolvedValue();
		log.mockImplementation(() => {});
		fs.unlinkSync.mockImplementation(() => {});
	});

	test('removes a main task and cleans dependencies across tags', async () => {
		const result = await removeTask('tasks/tasks.json', '1', { tag: 'master' });

		// Expect success true
		expect(result.success).toBe(true);
		// writeJSON called with data where task 1 is gone in master & dependencies removed in other tags
		const written = writeJSON.mock.calls[0][1];
		expect(written.master.tasks.find((t) => t.id === 1)).toBeUndefined();
		// deps removed from child tasks
		const task2 = written.master.tasks.find((t) => t.id === 2);
		expect(task2.dependencies).not.toContain(1);
		const shadow = written.other.tasks.find((t) => t.id === 99);
		expect(shadow.dependencies).not.toContain(1);
		// Task file deletion attempted
		expect(fs.unlinkSync).toHaveBeenCalled();
	});

	test('removes a subtask only and leaves parent intact', async () => {
		const result = await removeTask('tasks/tasks.json', '3.1', {
			tag: 'master'
		});

		expect(result.success).toBe(true);
		const written = writeJSON.mock.calls[0][1];
		const parent = written.master.tasks.find((t) => t.id === 3);
		expect(parent.subtasks || []).toHaveLength(0);
		// Ensure parent still exists
		expect(parent).toBeDefined();
		// No task files should be deleted for subtasks
		expect(fs.unlinkSync).not.toHaveBeenCalled();
	});

	test('handles non-existent task gracefully', async () => {
		const result = await removeTask('tasks/tasks.json', '42', {
			tag: 'master'
		});
		expect(result.success).toBe(false);
		expect(result.error).toContain('not found');
		// writeJSON not called because nothing changed
		expect(writeJSON).not.toHaveBeenCalled();
	});
});

```

--------------------------------------------------------------------------------
/tests/unit/prompts/expand-task-prompt.test.js:
--------------------------------------------------------------------------------

```javascript
import { jest } from '@jest/globals';
import { PromptManager } from '../../../scripts/modules/prompt-manager.js';

describe('expand-task prompt template', () => {
	let promptManager;

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

	const testTask = {
		id: 1,
		title: 'Setup AWS Infrastructure',
		description: 'Provision core AWS services',
		details: 'Create VPC, subnets, and security groups'
	};

	const baseParams = {
		task: testTask,
		subtaskCount: 3,
		nextSubtaskId: 1,
		additionalContext: '',
		complexityReasoningContext: '',
		gatheredContext: '',
		useResearch: false,
		expansionPrompt: undefined
	};

	test('default variant includes task context', () => {
		const { userPrompt } = promptManager.loadPrompt(
			'expand-task',
			baseParams,
			'default'
		);

		expect(userPrompt).toContain(testTask.title);
		expect(userPrompt).toContain(testTask.description);
		expect(userPrompt).toContain(testTask.details);
		expect(userPrompt).toContain('Task ID: 1');
	});

	test('research variant includes task context', () => {
		const params = { ...baseParams, useResearch: true };
		const { userPrompt } = promptManager.loadPrompt(
			'expand-task',
			params,
			'research'
		);

		expect(userPrompt).toContain(testTask.title);
		expect(userPrompt).toContain(testTask.description);
		expect(userPrompt).toContain(testTask.details);
		expect(userPrompt).toContain('Parent Task:');
		expect(userPrompt).toContain('ID: 1');
	});

	test('complexity-report variant includes task context', () => {
		const params = {
			...baseParams,
			expansionPrompt: 'Focus on security best practices',
			complexityReasoningContext: 'High complexity due to security requirements'
		};
		const { userPrompt } = promptManager.loadPrompt(
			'expand-task',
			params,
			'complexity-report'
		);

		// The fix ensures task context is included
		expect(userPrompt).toContain('Parent Task:');
		expect(userPrompt).toContain(`ID: ${testTask.id}`);
		expect(userPrompt).toContain(`Title: ${testTask.title}`);
		expect(userPrompt).toContain(`Description: ${testTask.description}`);
		expect(userPrompt).toContain(`Current details: ${testTask.details}`);

		// Also includes the expansion prompt
		expect(userPrompt).toContain('Expansion Guidance:');
		expect(userPrompt).toContain(params.expansionPrompt);
		expect(userPrompt).toContain(params.complexityReasoningContext);
	});

	test('all variants request JSON format with subtasks array', () => {
		const variants = ['default', 'research', 'complexity-report'];

		variants.forEach((variant) => {
			const params =
				variant === 'complexity-report'
					? { ...baseParams, expansionPrompt: 'test' }
					: baseParams;

			const { systemPrompt, userPrompt } = promptManager.loadPrompt(
				'expand-task',
				params,
				variant
			);
			const combined = systemPrompt + userPrompt;

			expect(combined.toLowerCase()).toContain('subtasks');
			expect(combined).toContain('JSON');
		});
	});

	test('complexity-report variant fails without task context regression test', () => {
		// This test ensures we don't regress to the old behavior where
		// complexity-report variant only used expansionPrompt without task context
		const params = {
			...baseParams,
			expansionPrompt: 'Generic expansion prompt'
		};

		const { userPrompt } = promptManager.loadPrompt(
			'expand-task',
			params,
			'complexity-report'
		);

		// Count occurrences of task-specific content
		const titleOccurrences = (
			userPrompt.match(new RegExp(testTask.title, 'g')) || []
		).length;
		const descriptionOccurrences = (
			userPrompt.match(new RegExp(testTask.description, 'g')) || []
		).length;

		// Should have at least one occurrence of title and description
		expect(titleOccurrences).toBeGreaterThanOrEqual(1);
		expect(descriptionOccurrences).toBeGreaterThanOrEqual(1);

		// Should not be ONLY the expansion prompt
		expect(userPrompt.length).toBeGreaterThan(
			params.expansionPrompt.length + 100
		);
	});
});

```

--------------------------------------------------------------------------------
/src/ai-providers/custom-sdk/grok-cli/errors.js:
--------------------------------------------------------------------------------

```javascript
/**
 * @fileoverview Error handling utilities for Grok CLI provider
 */

import { APICallError, LoadAPIKeyError } from '@ai-sdk/provider';

/**
 * @typedef {import('./types.js').GrokCliErrorMetadata} GrokCliErrorMetadata
 */

/**
 * Create an API call error with Grok CLI specific metadata
 * @param {Object} params - Error parameters
 * @param {string} params.message - Error message
 * @param {string} [params.code] - Error code
 * @param {number} [params.exitCode] - Process exit code
 * @param {string} [params.stderr] - Standard error output
 * @param {string} [params.stdout] - Standard output
 * @param {string} [params.promptExcerpt] - Excerpt of the prompt
 * @param {boolean} [params.isRetryable=false] - Whether the error is retryable
 * @returns {APICallError}
 */
export function createAPICallError({
	message,
	code,
	exitCode,
	stderr,
	stdout,
	promptExcerpt,
	isRetryable = false
}) {
	/** @type {GrokCliErrorMetadata} */
	const metadata = {
		code,
		exitCode,
		stderr,
		stdout,
		promptExcerpt
	};

	return new APICallError({
		message,
		isRetryable,
		url: 'grok-cli://command',
		requestBodyValues: promptExcerpt ? { prompt: promptExcerpt } : undefined,
		data: metadata
	});
}

/**
 * Create an authentication error
 * @param {Object} params - Error parameters
 * @param {string} params.message - Error message
 * @returns {LoadAPIKeyError}
 */
export function createAuthenticationError({ message }) {
	return new LoadAPIKeyError({
		message:
			message ||
			'Authentication failed. Please ensure Grok CLI is properly configured with API key.'
	});
}

/**
 * Create a timeout error
 * @param {Object} params - Error parameters
 * @param {string} params.message - Error message
 * @param {string} [params.promptExcerpt] - Excerpt of the prompt
 * @param {number} params.timeoutMs - Timeout in milliseconds
 * @returns {APICallError}
 */
export function createTimeoutError({ message, promptExcerpt, timeoutMs }) {
	/** @type {GrokCliErrorMetadata & { timeoutMs: number }} */
	const metadata = {
		code: 'TIMEOUT',
		promptExcerpt,
		timeoutMs
	};

	return new APICallError({
		message,
		isRetryable: true,
		url: 'grok-cli://command',
		requestBodyValues: promptExcerpt ? { prompt: promptExcerpt } : undefined,
		data: metadata
	});
}

/**
 * Create a CLI installation error
 * @param {Object} params - Error parameters
 * @param {string} [params.message] - Error message
 * @returns {APICallError}
 */
export function createInstallationError({ message }) {
	return new APICallError({
		message:
			message ||
			'Grok CLI is not installed or not found in PATH. Please install with: npm install -g @vibe-kit/grok-cli',
		isRetryable: false,
		url: 'grok-cli://installation'
	});
}

/**
 * Check if an error is an authentication error
 * @param {unknown} error - Error to check
 * @returns {boolean}
 */
export function isAuthenticationError(error) {
	if (error instanceof LoadAPIKeyError) return true;
	if (
		error instanceof APICallError &&
		/** @type {GrokCliErrorMetadata} */ (error.data)?.exitCode === 401
	)
		return true;
	return false;
}

/**
 * Check if an error is a timeout error
 * @param {unknown} error - Error to check
 * @returns {boolean}
 */
export function isTimeoutError(error) {
	if (
		error instanceof APICallError &&
		/** @type {GrokCliErrorMetadata} */ (error.data)?.code === 'TIMEOUT'
	)
		return true;
	return false;
}

/**
 * Check if an error is an installation error
 * @param {unknown} error - Error to check
 * @returns {boolean}
 */
export function isInstallationError(error) {
	if (error instanceof APICallError && error.url === 'grok-cli://installation')
		return true;
	return false;
}

/**
 * Get error metadata from an error
 * @param {unknown} error - Error to extract metadata from
 * @returns {GrokCliErrorMetadata|undefined}
 */
export function getErrorMetadata(error) {
	if (error instanceof APICallError && error.data) {
		return /** @type {GrokCliErrorMetadata} */ (error.data);
	}
	return undefined;
}

```

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

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

import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { promises as fs } from 'node:fs';
import { ConfigLoader } from './config-loader.service.js';
import { DEFAULT_CONFIG_VALUES } from '../../interfaces/configuration.interface.js';

vi.mock('node:fs', () => ({
	promises: {
		readFile: vi.fn(),
		access: vi.fn()
	}
}));

describe('ConfigLoader', () => {
	let configLoader: ConfigLoader;
	const testProjectRoot = '/test/project';

	beforeEach(() => {
		configLoader = new ConfigLoader(testProjectRoot);
		vi.clearAllMocks();
	});

	afterEach(() => {
		vi.restoreAllMocks();
	});

	describe('getDefaultConfig', () => {
		it('should return default configuration values', () => {
			const config = configLoader.getDefaultConfig();

			expect(config.models).toEqual({
				main: DEFAULT_CONFIG_VALUES.MODELS.MAIN,
				fallback: DEFAULT_CONFIG_VALUES.MODELS.FALLBACK
			});

			expect(config.storage).toEqual({
				type: DEFAULT_CONFIG_VALUES.STORAGE.TYPE,
				encoding: DEFAULT_CONFIG_VALUES.STORAGE.ENCODING,
				enableBackup: false,
				maxBackups: DEFAULT_CONFIG_VALUES.STORAGE.MAX_BACKUPS,
				enableCompression: false,
				atomicOperations: true
			});

			expect(config.version).toBe(DEFAULT_CONFIG_VALUES.VERSION);
		});
	});

	describe('loadLocalConfig', () => {
		it('should load and parse local configuration file', async () => {
			const mockConfig = {
				models: { main: 'test-model' },
				storage: { type: 'api' as const }
			};

			vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockConfig));

			const result = await configLoader.loadLocalConfig();

			expect(fs.readFile).toHaveBeenCalledWith(
				'/test/project/.taskmaster/config.json',
				'utf-8'
			);
			expect(result).toEqual(mockConfig);
		});

		it('should return null when config file does not exist', async () => {
			const error = new Error('File not found') as any;
			error.code = 'ENOENT';
			vi.mocked(fs.readFile).mockRejectedValue(error);

			const result = await configLoader.loadLocalConfig();

			expect(result).toBeNull();
		});

		it('should throw TaskMasterError for other file errors', async () => {
			const error = new Error('Permission denied');
			vi.mocked(fs.readFile).mockRejectedValue(error);

			await expect(configLoader.loadLocalConfig()).rejects.toThrow(
				'Failed to load local configuration'
			);
		});

		it('should throw error for invalid JSON', async () => {
			vi.mocked(fs.readFile).mockResolvedValue('invalid json');

			await expect(configLoader.loadLocalConfig()).rejects.toThrow();
		});
	});

	describe('loadGlobalConfig', () => {
		it('should return null (not implemented yet)', async () => {
			const result = await configLoader.loadGlobalConfig();
			expect(result).toBeNull();
		});
	});

	describe('hasLocalConfig', () => {
		it('should return true when local config exists', async () => {
			vi.mocked(fs.access).mockResolvedValue(undefined);

			const result = await configLoader.hasLocalConfig();

			expect(fs.access).toHaveBeenCalledWith(
				'/test/project/.taskmaster/config.json'
			);
			expect(result).toBe(true);
		});

		it('should return false when local config does not exist', async () => {
			vi.mocked(fs.access).mockRejectedValue(new Error('Not found'));

			const result = await configLoader.hasLocalConfig();

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

	describe('hasGlobalConfig', () => {
		it('should check global config path', async () => {
			vi.mocked(fs.access).mockResolvedValue(undefined);

			const result = await configLoader.hasGlobalConfig();

			expect(fs.access).toHaveBeenCalledWith(
				expect.stringContaining('.taskmaster/config.json')
			);
			expect(result).toBe(true);
		});

		it('should return false when global config does not exist', async () => {
			vi.mocked(fs.access).mockRejectedValue(new Error('Not found'));

			const result = await configLoader.hasGlobalConfig();

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

```

--------------------------------------------------------------------------------
/apps/extension/src/components/ui/shadcn-io/kanban/index.tsx:
--------------------------------------------------------------------------------

```typescript
'use client';

import { Card } from '@/components/ui/card';
import { cn } from '@/lib/utils';
import {
	DndContext,
	DragOverlay,
	MouseSensor,
	TouchSensor,
	rectIntersection,
	useDraggable,
	useDroppable,
	useSensor,
	useSensors
} from '@dnd-kit/core';
import type { DragEndEvent } from '@dnd-kit/core';
import type React from 'react';
import type { ReactNode } from 'react';

export type { DragEndEvent } from '@dnd-kit/core';

export type Status = {
	id: string;
	name: string;
	color: string;
};

export type Feature = {
	id: string;
	name: string;
	startAt: Date;
	endAt: Date;
	status: Status;
};

export type KanbanBoardProps = {
	id: Status['id'];
	children: ReactNode;
	className?: string;
};

export const KanbanBoard = ({ id, children, className }: KanbanBoardProps) => {
	const { isOver, setNodeRef } = useDroppable({ id });

	return (
		<div
			className={cn(
				'flex h-full min-h-40 flex-col gap-2 rounded-md border bg-secondary p-2 text-xs shadow-sm outline transition-all',
				isOver ? 'outline-primary' : 'outline-transparent',
				className
			)}
			ref={setNodeRef}
		>
			{children}
		</div>
	);
};

export type KanbanCardProps = Pick<Feature, 'id' | 'name'> & {
	index: number;
	parent: string;
	children?: ReactNode;
	className?: string;
	onClick?: (event: React.MouseEvent) => void;
	onDoubleClick?: (event: React.MouseEvent) => void;
};

export const KanbanCard = ({
	id,
	name,
	index,
	parent,
	children,
	className,
	onClick,
	onDoubleClick
}: KanbanCardProps) => {
	const { attributes, listeners, setNodeRef, transform, isDragging } =
		useDraggable({
			id,
			data: { index, parent }
		});

	return (
		<Card
			className={cn(
				'rounded-md p-3 shadow-sm',
				isDragging && 'cursor-grabbing opacity-0',
				!isDragging && 'cursor-pointer',
				className
			)}
			style={{
				transform: transform
					? `translateX(${transform.x}px) translateY(${transform.y}px)`
					: 'none'
			}}
			{...attributes}
			{...listeners}
			onClick={(e) => !isDragging && onClick?.(e)}
			onDoubleClick={onDoubleClick}
			ref={setNodeRef}
		>
			{children ?? <p className="m-0 font-medium text-sm">{name}</p>}
		</Card>
	);
};

export type KanbanCardsProps = {
	children: ReactNode;
	className?: string;
};

export const KanbanCards = ({ children, className }: KanbanCardsProps) => (
	<div className={cn('flex flex-1 flex-col gap-2', className)}>{children}</div>
);

export type KanbanHeaderProps =
	| {
			children: ReactNode;
	  }
	| {
			name: Status['name'];
			color: Status['color'];
			className?: string;
	  };

export const KanbanHeader = (props: KanbanHeaderProps) =>
	'children' in props ? (
		props.children
	) : (
		<div className={cn('flex shrink-0 items-center gap-2', props.className)}>
			<div
				className="h-2 w-2 rounded-full"
				style={{ backgroundColor: props.color }}
			/>
			<p className="m-0 font-semibold text-sm">{props.name}</p>
		</div>
	);

export type KanbanProviderProps = {
	children: ReactNode;
	onDragEnd: (event: DragEndEvent) => void;
	onDragStart?: (event: DragEndEvent) => void;
	onDragCancel?: () => void;
	className?: string;
	dragOverlay?: ReactNode;
};

export const KanbanProvider = ({
	children,
	onDragEnd,
	onDragStart,
	onDragCancel,
	className,
	dragOverlay
}: KanbanProviderProps) => {
	// Configure sensors with activation constraints to prevent accidental drags
	const sensors = useSensors(
		// Only start a drag if you've moved more than 8px
		useSensor(MouseSensor, {
			activationConstraint: { distance: 8 }
		}),
		// On touch devices, require a short press + small move
		useSensor(TouchSensor, {
			activationConstraint: { delay: 150, tolerance: 5 }
		})
	);

	return (
		<DndContext
			sensors={sensors}
			collisionDetection={rectIntersection}
			onDragEnd={onDragEnd}
			onDragStart={onDragStart}
			onDragCancel={onDragCancel}
		>
			<div
				className={cn(
					'grid w-full auto-cols-fr grid-flow-col gap-4',
					className
				)}
			>
				{children}
			</div>
			<DragOverlay>{dragOverlay}</DragOverlay>
		</DndContext>
	);
};

```

--------------------------------------------------------------------------------
/.taskmaster/docs/research/2025-06-14_test-save-functionality.md:
--------------------------------------------------------------------------------

```markdown
---
title: Research Session
query: "test save functionality"
date: 6/14/2025
time: 5:50:23 PM
timestamp: 2025-06-14T21:50:23.797Z
exchanges: 1
---

# Research Session

## Initial Query

**Question:** test save functionality

**Response:**

## Testing Save Functionality in a Task Management System

**Core Steps for Testing Save Functionality**

- Create or update a task in the system using the CLI or UI.
- Trigger the save operation (e.g., by issuing a command or clicking a save button).
- Verify that the data is correctly written to the persistent storage (e.g., `tasks.json`).
- Reload or re-query the data to ensure the saved changes persist and are accurately reflected.
- Validate that all required fields and relationships (such as dependencies and subtasks) are preserved and correctly structured.

**Key Test Scenarios**

- **Basic Save:** Add a new task and confirm it appears in `tasks.json` with all fields populated.
- **Update Save:** Modify an existing task (e.g., change status, description, or priority) and verify the changes are saved.
- **Subtask and Dependency Preservation:** Update a parent task and ensure that completed subtasks and dependency links remain intact, especially after using commands like `updateTask`.
- **Batch Operations:** Perform bulk updates or additions and confirm all affected tasks are saved correctly, with no data loss or corruption.
- **Validation:** Attempt to save invalid data and ensure the system rejects it or provides meaningful error messages, confirming validation logic is enforced.

**Recommended Practices**

- Use automated tests to simulate save operations for various scenarios, including edge cases (e.g., circular dependencies, missing required fields).
- After each save, reload the data and compare it to the expected state to ensure integrity.
- Log all save operations and errors for traceability and debugging.
- Regularly back up the `tasks.json` file to prevent data loss during testing and development.

**Relevant Features from Industry Standards**

- Task management systems typically provide robust save and update mechanisms, ensuring that all task attributes (including dependencies, subtasks, and comments) are consistently maintained[1][2][5].
- Validation and error handling are critical to prevent corrupt or incomplete saves, especially when handling complex relationships or batch operations[1][5].
- User feedback (such as success messages or error alerts) is important for confirming save actions and guiding users in case of issues[1][2].

**Example Test Case**

1. Create a task with subtasks and dependencies.
2. Mark some subtasks as complete.
3. Use the `updateTask` command to modify the parent task.
4. Save and reload the data.
5. Assert that:
   - The parent task reflects the updates.
   - Completed subtasks remain marked as complete.
   - Dependencies are unchanged and valid.

**Summary Table: Save Functionality Test Aspects**

| Aspect                | What to Test                                      | Expected Outcome                        |
|-----------------------|---------------------------------------------------|-----------------------------------------|
| Basic Save            | Add/update task, save, reload                     | Data persists and matches expectations  |
| Subtask Preservation  | Update parent, check subtask status               | Completed subtasks remain complete      |
| Dependency Handling   | Save with dependencies, reload                    | Dependencies are intact and valid       |
| Batch Operations      | Bulk save/update, reload                          | All changes persist, no data loss       |
| Validation            | Save invalid data                                 | Error is raised, data not corrupted     |

These steps and scenarios ensure that the save functionality is robust, reliable, and meets the requirements of a modern task management system[1][2][5].


---

*Generated by Task Master Research Command*  
*Timestamp: 2025-06-14T21:50:23.797Z*

```

--------------------------------------------------------------------------------
/packages/tm-core/src/utils/id-generator.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview ID generation utilities for Task Master
 * Provides functions to generate unique identifiers for tasks and subtasks
 */

import { randomBytes } from 'node:crypto';

/**
 * Generates a unique task ID using the format: TASK-{timestamp}-{random}
 *
 * @returns A unique task ID string
 * @example
 * ```typescript
 * const taskId = generateTaskId();
 * // Returns something like: "TASK-1704067200000-A7B3"
 * ```
 */
export function generateTaskId(): string {
	const timestamp = Date.now();
	const random = generateRandomString(4);
	return `TASK-${timestamp}-${random}`;
}

/**
 * Generates a subtask ID using the format: {parentId}.{sequential}
 *
 * @param parentId - The ID of the parent task
 * @param existingSubtasks - Array of existing subtask IDs to determine the next sequential number
 * @returns A unique subtask ID string
 * @example
 * ```typescript
 * const subtaskId = generateSubtaskId("TASK-123-A7B3", ["TASK-123-A7B3.1"]);
 * // Returns: "TASK-123-A7B3.2"
 * ```
 */
export function generateSubtaskId(
	parentId: string,
	existingSubtasks: string[] = []
): string {
	// Find existing subtasks for this parent
	const parentSubtasks = existingSubtasks.filter((id) =>
		id.startsWith(`${parentId}.`)
	);

	// Extract sequential numbers and find the highest
	const sequentialNumbers = parentSubtasks
		.map((id) => {
			const parts = id.split('.');
			const lastPart = parts[parts.length - 1];
			return Number.parseInt(lastPart, 10);
		})
		.filter((num) => !Number.isNaN(num))
		.sort((a, b) => a - b);

	// Determine the next sequential number
	const nextSequential =
		sequentialNumbers.length > 0 ? Math.max(...sequentialNumbers) + 1 : 1;

	return `${parentId}.${nextSequential}`;
}

/**
 * Generates a random alphanumeric string of specified length
 * Uses crypto.randomBytes for cryptographically secure randomness
 *
 * @param length - The desired length of the random string
 * @returns A random alphanumeric string
 * @internal
 */
function generateRandomString(length: number): string {
	const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
	const bytes = randomBytes(length);
	let result = '';

	for (let i = 0; i < length; i++) {
		result += chars[bytes[i] % chars.length];
	}

	return result;
}

/**
 * Validates a task ID format
 *
 * @param id - The ID to validate
 * @returns True if the ID matches the expected task ID format
 * @example
 * ```typescript
 * isValidTaskId("TASK-1704067200000-A7B3"); // true
 * isValidTaskId("invalid-id"); // false
 * ```
 */
export function isValidTaskId(id: string): boolean {
	const taskIdRegex = /^TASK-\d{13}-[A-Z0-9]{4}$/;
	return taskIdRegex.test(id);
}

/**
 * Validates a subtask ID format
 *
 * @param id - The ID to validate
 * @returns True if the ID matches the expected subtask ID format
 * @example
 * ```typescript
 * isValidSubtaskId("TASK-1704067200000-A7B3.1"); // true
 * isValidSubtaskId("TASK-1704067200000-A7B3.1.2"); // true (nested subtask)
 * isValidSubtaskId("invalid.id"); // false
 * ```
 */
export function isValidSubtaskId(id: string): boolean {
	const parts = id.split('.');
	if (parts.length < 2) return false;

	// First part should be a valid task ID
	const taskIdPart = parts[0];
	if (!isValidTaskId(taskIdPart)) return false;

	// Remaining parts should be positive integers
	const sequentialParts = parts.slice(1);
	return sequentialParts.every((part) => {
		const num = Number.parseInt(part, 10);
		return !Number.isNaN(num) && num > 0 && part === num.toString();
	});
}

/**
 * Extracts the parent task ID from a subtask ID
 *
 * @param subtaskId - The subtask ID
 * @returns The parent task ID, or null if the input is not a valid subtask ID
 * @example
 * ```typescript
 * getParentTaskId("TASK-1704067200000-A7B3.1.2"); // "TASK-1704067200000-A7B3"
 * getParentTaskId("TASK-1704067200000-A7B3"); // null (not a subtask)
 * ```
 */
export function getParentTaskId(subtaskId: string): string | null {
	if (!isValidSubtaskId(subtaskId)) return null;

	const parts = subtaskId.split('.');
	return parts[0];
}

```

--------------------------------------------------------------------------------
/apps/extension/src/services/task-repository.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Task Repository - Simplified version
 * Handles data access with caching
 */

import { EventEmitter } from '../utils/event-emitter';
import type { ExtensionLogger } from '../utils/logger';
import type { TaskMasterApi, TaskMasterTask } from '../utils/task-master-api';

// Use the TaskMasterTask type directly to ensure compatibility
export type Task = TaskMasterTask;

export class TaskRepository extends EventEmitter {
	private cache: Task[] | null = null;
	private cacheTimestamp = 0;
	private readonly CACHE_DURATION = 30000; // 30 seconds

	constructor(
		private api: TaskMasterApi,
		private logger: ExtensionLogger
	) {
		super();
	}

	async getAll(options?: {
		tag?: string;
		withSubtasks?: boolean;
	}): Promise<Task[]> {
		// If a tag is specified, always fetch fresh data
		const shouldUseCache =
			!options?.tag &&
			this.cache &&
			Date.now() - this.cacheTimestamp < this.CACHE_DURATION;

		if (shouldUseCache) {
			return this.cache || [];
		}

		try {
			const result = await this.api.getTasks({
				withSubtasks: options?.withSubtasks ?? true,
				tag: options?.tag
			});

			if (result.success && result.data) {
				this.cache = result.data;
				this.cacheTimestamp = Date.now();
				this.emit('tasks:updated', result.data);
				return result.data;
			}

			throw new Error(result.error || 'Failed to fetch tasks');
		} catch (error) {
			this.logger.error('Failed to get tasks', error);
			throw error;
		}
	}

	async getById(taskId: string): Promise<Task | null> {
		// First check cache
		if (this.cache) {
			// Handle both main tasks and subtasks
			for (const task of this.cache) {
				if (task.id === taskId) {
					return task;
				}
				// Check subtasks
				if (task.subtasks) {
					for (const subtask of task.subtasks) {
						if (
							subtask.id.toString() === taskId ||
							`${task.id}.${subtask.id}` === taskId
						) {
							return {
								...subtask,
								id: subtask.id.toString(),
								description: subtask.description || '',
								status: (subtask.status ||
									'pending') as TaskMasterTask['status'],
								priority: 'medium' as const,
								dependencies:
									subtask.dependencies?.map((d) => d.toString()) || []
							};
						}
					}
				}
			}
		}

		// If not in cache, fetch all and search
		const tasks = await this.getAll();
		for (const task of tasks) {
			if (task.id === taskId) {
				return task;
			}
			// Check subtasks
			if (task.subtasks) {
				for (const subtask of task.subtasks) {
					if (
						subtask.id.toString() === taskId ||
						`${task.id}.${subtask.id}` === taskId
					) {
						return {
							...subtask,
							id: subtask.id.toString(),
							description: subtask.description || '',
							status: (subtask.status || 'pending') as TaskMasterTask['status'],
							priority: 'medium' as const,
							dependencies: subtask.dependencies?.map((d) => d.toString()) || []
						};
					}
				}
			}
		}

		return null;
	}

	async updateStatus(taskId: string, status: Task['status']): Promise<void> {
		try {
			const result = await this.api.updateTaskStatus(taskId, status);

			if (!result.success) {
				throw new Error(result.error || 'Failed to update status');
			}

			// Invalidate cache
			this.cache = null;

			// Fetch updated tasks
			await this.getAll();
		} catch (error) {
			this.logger.error('Failed to update task status', error);
			throw error;
		}
	}

	async updateContent(taskId: string, updates: any): Promise<void> {
		try {
			const result = await this.api.updateTask(taskId, updates, {
				append: false,
				research: false
			});

			if (!result.success) {
				throw new Error(result.error || 'Failed to update task');
			}

			// Invalidate cache
			this.cache = null;

			// Fetch updated tasks
			await this.getAll();
		} catch (error) {
			this.logger.error('Failed to update task content', error);
			throw error;
		}
	}

	async refresh(): Promise<void> {
		this.cache = null;
		await this.getAll();
	}

	isConnected(): boolean {
		return this.api.getConnectionStatus().isConnected;
	}
}

```

--------------------------------------------------------------------------------
/packages/tm-core/src/config/services/environment-config-provider.service.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @fileoverview Environment Configuration Provider
 * Extracts configuration from environment variables
 */

import type { PartialConfiguration } from '../../interfaces/configuration.interface.js';

/**
 * Environment variable mapping definition
 */
interface EnvMapping {
	/** Environment variable name */
	env: string;
	/** Path in configuration object */
	path: readonly string[];
	/** Optional validator function */
	validate?: (value: string) => boolean;
	/** Whether this is runtime state (not configuration) */
	isRuntimeState?: boolean;
}

/**
 * EnvironmentConfigProvider extracts configuration from environment variables
 * Single responsibility: Environment variable configuration extraction
 */
export class EnvironmentConfigProvider {
	/**
	 * Default environment variable mappings
	 */
	private static readonly DEFAULT_MAPPINGS: EnvMapping[] = [
		{
			env: 'TASKMASTER_STORAGE_TYPE',
			path: ['storage', 'type'],
			validate: (v: string) => ['file', 'api'].includes(v)
		},
		{ env: 'TASKMASTER_API_ENDPOINT', path: ['storage', 'apiEndpoint'] },
		{ env: 'TASKMASTER_API_TOKEN', path: ['storage', 'apiAccessToken'] },
		{ env: 'TASKMASTER_MODEL_MAIN', path: ['models', 'main'] },
		{ env: 'TASKMASTER_MODEL_RESEARCH', path: ['models', 'research'] },
		{ env: 'TASKMASTER_MODEL_FALLBACK', path: ['models', 'fallback'] },
		{
			env: 'TASKMASTER_RESPONSE_LANGUAGE',
			path: ['custom', 'responseLanguage']
		}
	];

	/**
	 * Runtime state mappings (separate from configuration)
	 */
	private static readonly RUNTIME_STATE_MAPPINGS: EnvMapping[] = [
		{ env: 'TASKMASTER_TAG', path: ['activeTag'], isRuntimeState: true }
	];

	private mappings: EnvMapping[];

	constructor(customMappings?: EnvMapping[]) {
		this.mappings = customMappings || [
			...EnvironmentConfigProvider.DEFAULT_MAPPINGS,
			...EnvironmentConfigProvider.RUNTIME_STATE_MAPPINGS
		];
	}

	/**
	 * Load configuration from environment variables
	 */
	loadConfig(): PartialConfiguration {
		const config: PartialConfiguration = {};

		for (const mapping of this.mappings) {
			// Skip runtime state variables
			if (mapping.isRuntimeState) continue;

			const value = process.env[mapping.env];
			if (!value) continue;

			// Validate value if validator is provided
			if (mapping.validate && !mapping.validate(value)) {
				console.warn(`Invalid value for ${mapping.env}: ${value}`);
				continue;
			}

			// Set the value in the config object
			this.setNestedProperty(config, mapping.path, value);
		}

		return config;
	}

	/**
	 * Get runtime state from environment variables
	 */
	getRuntimeState(): Record<string, string> {
		const state: Record<string, string> = {};

		for (const mapping of this.mappings) {
			if (!mapping.isRuntimeState) continue;

			const value = process.env[mapping.env];
			if (value) {
				const key = mapping.path[mapping.path.length - 1];
				state[key] = value;
			}
		}

		return state;
	}

	/**
	 * Helper to set a nested property in an object
	 */
	private setNestedProperty(
		obj: any,
		path: readonly string[],
		value: any
	): void {
		const lastKey = path[path.length - 1];
		const keys = path.slice(0, -1);

		let current = obj;
		for (const key of keys) {
			if (!current[key]) {
				current[key] = {};
			}
			current = current[key];
		}

		current[lastKey] = value;
	}

	/**
	 * Check if an environment variable is set
	 */
	hasEnvVar(envName: string): boolean {
		return envName in process.env && process.env[envName] !== undefined;
	}

	/**
	 * Get all environment variables that match our prefix
	 */
	getAllTaskmasterEnvVars(): Record<string, string> {
		const vars: Record<string, string> = {};
		const prefix = 'TASKMASTER_';

		for (const [key, value] of Object.entries(process.env)) {
			if (key.startsWith(prefix) && value !== undefined) {
				vars[key] = value;
			}
		}

		return vars;
	}

	/**
	 * Add a custom mapping
	 */
	addMapping(mapping: EnvMapping): void {
		this.mappings.push(mapping);
	}

	/**
	 * Get current mappings
	 */
	getMappings(): EnvMapping[] {
		return [...this.mappings];
	}
}

```

--------------------------------------------------------------------------------
/mcp-server/src/custom-sdk/schema-converter.js:
--------------------------------------------------------------------------------

```javascript
/**
 * @fileoverview Schema conversion utilities for MCP AI SDK provider
 */

/**
 * Convert Zod schema to human-readable JSON instructions
 * @param {import('zod').ZodSchema} schema - Zod schema object
 * @param {string} [objectName='result'] - Name of the object being generated
 * @returns {string} Instructions for JSON generation
 */
export function convertSchemaToInstructions(schema, objectName = 'result') {
	try {
		// Generate example structure from schema
		const exampleStructure = generateExampleFromSchema(schema);

		return `
CRITICAL JSON GENERATION INSTRUCTIONS:

You must respond with ONLY valid JSON that matches this exact structure for "${objectName}":

${JSON.stringify(exampleStructure, null, 2)}

STRICT REQUIREMENTS:
1. Response must start with { and end with }
2. Use double quotes for all strings and property names
3. Do not include any text before or after the JSON
4. Do not wrap in markdown code blocks
5. Do not include explanations or comments
6. Follow the exact property names and types shown above
7. All required fields must be present

Begin your response immediately with the opening brace {`;
	} catch (error) {
		// Fallback to basic JSON instructions if schema parsing fails
		return `
CRITICAL JSON GENERATION INSTRUCTIONS:

You must respond with ONLY valid JSON for "${objectName}".

STRICT REQUIREMENTS:
1. Response must start with { and end with }
2. Use double quotes for all strings and property names  
3. Do not include any text before or after the JSON
4. Do not wrap in markdown code blocks
5. Do not include explanations or comments

Begin your response immediately with the opening brace {`;
	}
}

/**
 * Generate example structure from Zod schema
 * @param {import('zod').ZodSchema} schema - Zod schema
 * @returns {any} Example object matching the schema
 */
function generateExampleFromSchema(schema) {
	// This is a simplified schema-to-example converter
	// For production, you might want to use a more sophisticated library

	if (!schema || typeof schema._def === 'undefined') {
		return {};
	}

	const def = schema._def;

	switch (def.typeName) {
		case 'ZodObject':
			const result = {};
			const shape = def.shape();

			for (const [key, fieldSchema] of Object.entries(shape)) {
				result[key] = generateExampleFromSchema(fieldSchema);
			}

			return result;

		case 'ZodString':
			return 'string';

		case 'ZodNumber':
			return 0;

		case 'ZodBoolean':
			return false;

		case 'ZodArray':
			const elementExample = generateExampleFromSchema(def.type);
			return [elementExample];

		case 'ZodOptional':
			return generateExampleFromSchema(def.innerType);

		case 'ZodNullable':
			return generateExampleFromSchema(def.innerType);

		case 'ZodEnum':
			return def.values[0] || 'enum_value';

		case 'ZodLiteral':
			return def.value;

		case 'ZodUnion':
			// Use the first option from the union
			if (def.options && def.options.length > 0) {
				return generateExampleFromSchema(def.options[0]);
			}
			return 'union_value';

		case 'ZodRecord':
			return {
				key: generateExampleFromSchema(def.valueType)
			};

		default:
			// For unknown types, return a placeholder
			return `<${def.typeName || 'unknown'}>`;
	}
}

/**
 * Enhance prompt with JSON generation instructions
 * @param {Array} prompt - AI SDK prompt array
 * @param {string} jsonInstructions - JSON generation instructions
 * @returns {Array} Enhanced prompt array
 */
export function enhancePromptForJSON(prompt, jsonInstructions) {
	const enhancedPrompt = [...prompt];

	// Find system message or create one
	let systemMessageIndex = enhancedPrompt.findIndex(
		(msg) => msg.role === 'system'
	);

	if (systemMessageIndex >= 0) {
		// Append to existing system message
		const currentContent = enhancedPrompt[systemMessageIndex].content;
		enhancedPrompt[systemMessageIndex] = {
			...enhancedPrompt[systemMessageIndex],
			content: currentContent + '\n\n' + jsonInstructions
		};
	} else {
		// Add new system message at the beginning
		enhancedPrompt.unshift({
			role: 'system',
			content: jsonInstructions
		});
	}

	return enhancedPrompt;
}

```

--------------------------------------------------------------------------------
/.claude/TM_COMMANDS_GUIDE.md:
--------------------------------------------------------------------------------

```markdown
# Task Master Commands for Claude Code

Complete guide to using Task Master through Claude Code's slash commands.

## Overview

All Task Master functionality is available through the `/project:tm/` namespace with natural language support and intelligent features.

## Quick Start

```bash
# Install Task Master
/project:tm/setup/quick-install

# Initialize project
/project:tm/init/quick

# Parse requirements
/project:tm/parse-prd requirements.md

# Start working
/project:tm/next
```

## Command Structure

Commands are organized hierarchically to match Task Master's CLI:
- Main commands at `/project:tm/[command]`
- Subcommands for specific operations `/project:tm/[command]/[subcommand]`
- Natural language arguments accepted throughout

## Complete Command Reference

### Setup & Configuration
- `/project:tm/setup/install` - Full installation guide
- `/project:tm/setup/quick-install` - One-line install
- `/project:tm/init` - Initialize project
- `/project:tm/init/quick` - Quick init with -y
- `/project:tm/models` - View AI config
- `/project:tm/models/setup` - Configure AI

### Task Generation
- `/project:tm/parse-prd` - Generate from PRD
- `/project:tm/parse-prd/with-research` - Enhanced parsing
- `/project:tm/generate` - Create task files

### Task Management
- `/project:tm/list` - List with natural language filters
- `/project:tm/list/with-subtasks` - Hierarchical view
- `/project:tm/list/by-status <status>` - Filter by status
- `/project:tm/show <id>` - Task details
- `/project:tm/add-task` - Create task
- `/project:tm/update` - Update tasks
- `/project:tm/remove-task` - Delete task

### Status Management
- `/project:tm/set-status/to-pending <id>`
- `/project:tm/set-status/to-in-progress <id>`
- `/project:tm/set-status/to-done <id>`
- `/project:tm/set-status/to-review <id>`
- `/project:tm/set-status/to-deferred <id>`
- `/project:tm/set-status/to-cancelled <id>`

### Task Analysis
- `/project:tm/analyze-complexity` - AI analysis
- `/project:tm/complexity-report` - View report
- `/project:tm/expand <id>` - Break down task
- `/project:tm/expand/all` - Expand all complex

### Dependencies
- `/project:tm/add-dependency` - Add dependency
- `/project:tm/remove-dependency` - Remove dependency
- `/project:tm/validate-dependencies` - Check issues
- `/project:tm/fix-dependencies` - Auto-fix

### Workflows
- `/project:tm/workflows/smart-flow` - Adaptive workflows
- `/project:tm/workflows/pipeline` - Chain commands
- `/project:tm/workflows/auto-implement` - AI implementation

### Utilities
- `/project:tm/status` - Project dashboard
- `/project:tm/next` - Next task recommendation
- `/project:tm/utils/analyze` - Project analysis
- `/project:tm/learn` - Interactive help

## Key Features

### Natural Language Support
All commands understand natural language:
```
/project:tm/list pending high priority
/project:tm/update mark 23 as done
/project:tm/add-task implement OAuth login
```

### Smart Context
Commands analyze project state and provide intelligent suggestions based on:
- Current task status
- Dependencies
- Team patterns
- Project phase

### Visual Enhancements
- Progress bars and indicators
- Status badges
- Organized displays
- Clear hierarchies

## Common Workflows

### Daily Development
```
/project:tm/workflows/smart-flow morning
/project:tm/next
/project:tm/set-status/to-in-progress <id>
/project:tm/set-status/to-done <id>
```

### Task Breakdown
```
/project:tm/show <id>
/project:tm/expand <id>
/project:tm/list/with-subtasks
```

### Sprint Planning
```
/project:tm/analyze-complexity
/project:tm/workflows/pipeline init → expand/all → status
```

## Migration from Old Commands

| Old | New |
|-----|-----|
| `/project:task-master:list` | `/project:tm/list` |
| `/project:task-master:complete` | `/project:tm/set-status/to-done` |
| `/project:workflows:auto-implement` | `/project:tm/workflows/auto-implement` |

## Tips

1. Use `/project:tm/` + Tab for command discovery
2. Natural language is supported everywhere
3. Commands provide smart defaults
4. Chain commands for automation
5. Check `/project:tm/learn` for interactive help
```

--------------------------------------------------------------------------------
/assets/claude/TM_COMMANDS_GUIDE.md:
--------------------------------------------------------------------------------

```markdown
# Task Master Commands for Claude Code

Complete guide to using Task Master through Claude Code's slash commands.

## Overview

All Task Master functionality is available through the `/project:tm/` namespace with natural language support and intelligent features.

## Quick Start

```bash
# Install Task Master
/project:tm/setup/quick-install

# Initialize project
/project:tm/init/quick

# Parse requirements
/project:tm/parse-prd requirements.md

# Start working
/project:tm/next
```

## Command Structure

Commands are organized hierarchically to match Task Master's CLI:
- Main commands at `/project:tm/[command]`
- Subcommands for specific operations `/project:tm/[command]/[subcommand]`
- Natural language arguments accepted throughout

## Complete Command Reference

### Setup & Configuration
- `/project:tm/setup/install` - Full installation guide
- `/project:tm/setup/quick-install` - One-line install
- `/project:tm/init` - Initialize project
- `/project:tm/init/quick` - Quick init with -y
- `/project:tm/models` - View AI config
- `/project:tm/models/setup` - Configure AI

### Task Generation
- `/project:tm/parse-prd` - Generate from PRD
- `/project:tm/parse-prd/with-research` - Enhanced parsing
- `/project:tm/generate` - Create task files

### Task Management
- `/project:tm/list` - List with natural language filters
- `/project:tm/list/with-subtasks` - Hierarchical view
- `/project:tm/list/by-status <status>` - Filter by status
- `/project:tm/show <id>` - Task details
- `/project:tm/add-task` - Create task
- `/project:tm/update` - Update tasks
- `/project:tm/remove-task` - Delete task

### Status Management
- `/project:tm/set-status/to-pending <id>`
- `/project:tm/set-status/to-in-progress <id>`
- `/project:tm/set-status/to-done <id>`
- `/project:tm/set-status/to-review <id>`
- `/project:tm/set-status/to-deferred <id>`
- `/project:tm/set-status/to-cancelled <id>`

### Task Analysis
- `/project:tm/analyze-complexity` - AI analysis
- `/project:tm/complexity-report` - View report
- `/project:tm/expand <id>` - Break down task
- `/project:tm/expand/all` - Expand all complex

### Dependencies
- `/project:tm/add-dependency` - Add dependency
- `/project:tm/remove-dependency` - Remove dependency
- `/project:tm/validate-dependencies` - Check issues
- `/project:tm/fix-dependencies` - Auto-fix

### Workflows
- `/project:tm/workflows/smart-flow` - Adaptive workflows
- `/project:tm/workflows/pipeline` - Chain commands
- `/project:tm/workflows/auto-implement` - AI implementation

### Utilities
- `/project:tm/status` - Project dashboard
- `/project:tm/next` - Next task recommendation
- `/project:tm/utils/analyze` - Project analysis
- `/project:tm/learn` - Interactive help

## Key Features

### Natural Language Support
All commands understand natural language:
```
/project:tm/list pending high priority
/project:tm/update mark 23 as done
/project:tm/add-task implement OAuth login
```

### Smart Context
Commands analyze project state and provide intelligent suggestions based on:
- Current task status
- Dependencies
- Team patterns
- Project phase

### Visual Enhancements
- Progress bars and indicators
- Status badges
- Organized displays
- Clear hierarchies

## Common Workflows

### Daily Development
```
/project:tm/workflows/smart-flow morning
/project:tm/next
/project:tm/set-status/to-in-progress <id>
/project:tm/set-status/to-done <id>
```

### Task Breakdown
```
/project:tm/show <id>
/project:tm/expand <id>
/project:tm/list/with-subtasks
```

### Sprint Planning
```
/project:tm/analyze-complexity
/project:tm/workflows/pipeline init → expand/all → status
```

## Migration from Old Commands

| Old | New |
|-----|-----|
| `/project:task-master:list` | `/project:tm/list` |
| `/project:task-master:complete` | `/project:tm/set-status/to-done` |
| `/project:workflows:auto-implement` | `/project:tm/workflows/auto-implement` |

## Tips

1. Use `/project:tm/` + Tab for command discovery
2. Natural language is supported everywhere
3. Commands provide smart defaults
4. Chain commands for automation
5. Check `/project:tm/learn` for interactive help
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/clear-subtasks.js:
--------------------------------------------------------------------------------

```javascript
/**
 * Direct function wrapper for clearSubtasks
 */

import { clearSubtasks } from '../../../../scripts/modules/task-manager.js';
import {
	enableSilentMode,
	disableSilentMode,
	readJSON
} from '../../../../scripts/modules/utils.js';
import fs from 'fs';
import path from 'path';

/**
 * Clear subtasks from specified tasks
 * @param {Object} args - Function arguments
 * @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
 * @param {string} [args.id] - Task IDs (comma-separated) to clear subtasks from
 * @param {boolean} [args.all] - Clear subtasks from all tasks
 * @param {string} [args.tag] - Tag context to operate on (defaults to current active tag)
 * @param {string} [args.projectRoot] - Project root path (for MCP/env fallback)
 * @param {Object} log - Logger object
 * @returns {Promise<{success: boolean, data?: Object, error?: {code: string, message: string}}>}
 */
export async function clearSubtasksDirect(args, log) {
	// Destructure expected args
	const { tasksJsonPath, id, all, tag, projectRoot } = args;
	try {
		log.info(`Clearing subtasks with args: ${JSON.stringify(args)}`);

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

		// Either id or all must be provided
		if (!id && !all) {
			return {
				success: false,
				error: {
					code: 'INPUT_VALIDATION_ERROR',
					message:
						'Either task IDs with id parameter or all parameter must be provided'
				}
			};
		}

		// Use provided path
		const tasksPath = tasksJsonPath;

		// Check if tasks.json exists
		if (!fs.existsSync(tasksPath)) {
			return {
				success: false,
				error: {
					code: 'FILE_NOT_FOUND_ERROR',
					message: `Tasks file not found at ${tasksPath}`
				}
			};
		}

		let taskIds;

		// Use readJSON which handles silent migration and tag resolution
		const data = readJSON(tasksPath, projectRoot, tag);

		if (!data || !data.tasks) {
			return {
				success: false,
				error: {
					code: 'INPUT_VALIDATION_ERROR',
					message: `No tasks found in tasks file: ${tasksPath}`
				}
			};
		}

		const currentTag = data.tag || tag;
		const tasks = data.tasks;

		// If all is specified, get all task IDs
		if (all) {
			log.info(`Clearing subtasks from all tasks in tag '${currentTag}'`);
			if (tasks.length === 0) {
				return {
					success: false,
					error: {
						code: 'INPUT_VALIDATION_ERROR',
						message: `No tasks found in tag context '${currentTag}'`
					}
				};
			}
			taskIds = tasks.map((t) => t.id).join(',');
		} else {
			// Use the provided task IDs
			taskIds = id;
		}

		log.info(`Clearing subtasks from tasks: ${taskIds} in tag '${currentTag}'`);

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

		// Call the core function
		clearSubtasks(tasksPath, taskIds, { projectRoot, tag: currentTag });

		// Restore normal logging
		disableSilentMode();

		// Read the updated data to provide a summary
		const updatedData = readJSON(tasksPath, projectRoot, currentTag);
		const taskIdArray = taskIds.split(',').map((id) => parseInt(id.trim(), 10));

		// Build a summary of what was done
		const clearedTasksCount = taskIdArray.length;
		const updatedTasks = updatedData.tasks || [];

		const taskSummary = taskIdArray.map((id) => {
			const task = updatedTasks.find((t) => t.id === id);
			return task ? { id, title: task.title } : { id, title: 'Task not found' };
		});

		return {
			success: true,
			data: {
				message: `Successfully cleared subtasks from ${clearedTasksCount} task(s) in tag '${currentTag}'`,
				tasksCleared: taskSummary,
				tag: currentTag
			}
		};
	} catch (error) {
		// Make sure to restore normal logging even if there's an error
		disableSilentMode();

		log.error(`Error in clearSubtasksDirect: ${error.message}`);
		return {
			success: false,
			error: {
				code: 'CORE_FUNCTION_ERROR',
				message: error.message
			}
		};
	}
}

```

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

```javascript
/**
 * tools/get-task.js
 * Tool to get task details by ID
 */

import { z } from 'zod';
import {
	handleApiResult,
	createErrorResponse,
	withNormalizedProjectRoot
} from './utils.js';
import { showTaskDirect } from '../core/task-master-core.js';
import {
	findTasksPath,
	findComplexityReportPath
} from '../core/utils/path-utils.js';
import { resolveTag } from '../../../scripts/modules/utils.js';

/**
 * Custom processor function that removes allTasks from the response
 * @param {Object} data - The data returned from showTaskDirect
 * @returns {Object} - The processed data with allTasks removed
 */
function processTaskResponse(data) {
	if (!data) return data;

	// If we have the expected structure with task and allTasks
	if (typeof data === 'object' && data !== null && data.id && data.title) {
		// If the data itself looks like the task object, return it
		return data;
	} else if (data.task) {
		return data.task;
	}

	// If structure is unexpected, return as is
	return data;
}

/**
 * Register the get-task tool with the MCP server
 * @param {Object} server - FastMCP server instance
 */
export function registerShowTaskTool(server) {
	server.addTool({
		name: 'get_task',
		description: 'Get detailed information about a specific task',
		parameters: z.object({
			id: z
				.string()
				.describe(
					'Task ID(s) to get (can be comma-separated for multiple tasks)'
				),
			status: z
				.string()
				.optional()
				.describe("Filter subtasks by status (e.g., 'pending', 'done')"),
			file: z
				.string()
				.optional()
				.describe('Path to the tasks file relative to project root'),
			complexityReport: z
				.string()
				.optional()
				.describe(
					'Path to the complexity report file (relative to project root or absolute)'
				),
			projectRoot: z
				.string()
				.describe(
					'Absolute path to the project root directory (Optional, usually from session)'
				),
			tag: z.string().optional().describe('Tag context to operate on')
		}),
		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
			const { id, file, status, projectRoot } = args;

			try {
				log.info(
					`Getting task details for ID: ${id}${status ? ` (filtering subtasks by status: ${status})` : ''} in root: ${projectRoot}`
				);
				const resolvedTag = resolveTag({
					projectRoot: args.projectRoot,
					tag: args.tag
				});

				// Resolve the path to tasks.json using the NORMALIZED projectRoot from args
				let tasksJsonPath;
				try {
					tasksJsonPath = findTasksPath(
						{ projectRoot: projectRoot, file: file },
						log
					);
					log.info(`Resolved tasks path: ${tasksJsonPath}`);
				} catch (error) {
					log.error(`Error finding tasks.json: ${error.message}`);
					return createErrorResponse(
						`Failed to find tasks.json: ${error.message}`
					);
				}

				// Call the direct function, passing the normalized projectRoot
				// Resolve the path to complexity report
				let complexityReportPath;
				try {
					complexityReportPath = findComplexityReportPath(
						{
							projectRoot: projectRoot,
							complexityReport: args.complexityReport,
							tag: resolvedTag
						},
						log
					);
				} catch (error) {
					log.error(`Error finding complexity report: ${error.message}`);
				}
				const result = await showTaskDirect(
					{
						tasksJsonPath: tasksJsonPath,
						reportPath: complexityReportPath,
						// Pass other relevant args
						id: id,
						status: status,
						projectRoot: projectRoot,
						tag: resolvedTag
					},
					log,
					{ session }
				);

				if (result.success) {
					log.info(`Successfully retrieved task details for ID: ${args.id}`);
				} else {
					log.error(`Failed to get task: ${result.error.message}`);
				}

				// Use our custom processor function
				return handleApiResult(
					result,
					log,
					'Error retrieving task details',
					processTaskResponse,
					projectRoot
				);
			} catch (error) {
				log.error(`Error in get-task tool: ${error.message}\n${error.stack}`);
				return createErrorResponse(`Failed to get task: ${error.message}`);
			}
		})
	});
}

```

--------------------------------------------------------------------------------
/scripts/modules/task-manager/remove-subtask.js:
--------------------------------------------------------------------------------

```javascript
import path from 'path';
import { log, readJSON, writeJSON } from '../utils.js';
import generateTaskFiles from './generate-task-files.js';

/**
 * Remove a subtask from its parent task
 * @param {string} tasksPath - Path to the tasks.json file
 * @param {string} subtaskId - ID of the subtask to remove in format "parentId.subtaskId"
 * @param {boolean} convertToTask - Whether to convert the subtask to a standalone task
 * @param {boolean} generateFiles - Whether to regenerate task files after removing the subtask
 * @param {Object} context - Context object containing projectRoot and tag information
 * @param {string} [context.projectRoot] - Project root path
 * @param {string} [context.tag] - Tag for the task
 * @returns {Object|null} The removed subtask if convertToTask is true, otherwise null
 */
async function removeSubtask(
	tasksPath,
	subtaskId,
	convertToTask = false,
	generateFiles = false,
	context = {}
) {
	const { projectRoot, tag } = context;
	try {
		log('info', `Removing subtask ${subtaskId}...`);

		// Read the existing tasks with proper context
		const data = readJSON(tasksPath, projectRoot, tag);
		if (!data || !data.tasks) {
			throw new Error(`Invalid or missing tasks file at ${tasksPath}`);
		}

		// Parse the subtask ID (format: "parentId.subtaskId")
		if (!subtaskId.includes('.')) {
			throw new Error(
				`Invalid subtask ID format: ${subtaskId}. Expected format: "parentId.subtaskId"`
			);
		}

		const [parentIdStr, subtaskIdStr] = subtaskId.split('.');
		const parentId = parseInt(parentIdStr, 10);
		const subtaskIdNum = parseInt(subtaskIdStr, 10);

		// Find the parent task
		const parentTask = data.tasks.find((t) => t.id === parentId);
		if (!parentTask) {
			throw new Error(`Parent task with ID ${parentId} not found`);
		}

		// Check if parent has subtasks
		if (!parentTask.subtasks || parentTask.subtasks.length === 0) {
			throw new Error(`Parent task ${parentId} has no subtasks`);
		}

		// Find the subtask to remove
		const subtaskIndex = parentTask.subtasks.findIndex(
			(st) => st.id === subtaskIdNum
		);
		if (subtaskIndex === -1) {
			throw new Error(`Subtask ${subtaskId} not found`);
		}

		// Get a copy of the subtask before removing it
		const removedSubtask = { ...parentTask.subtasks[subtaskIndex] };

		// Remove the subtask from the parent
		parentTask.subtasks.splice(subtaskIndex, 1);

		// If parent has no more subtasks, remove the subtasks array
		if (parentTask.subtasks.length === 0) {
			parentTask.subtasks = undefined;
		}

		let convertedTask = null;

		// Convert the subtask to a standalone task if requested
		if (convertToTask) {
			log('info', `Converting subtask ${subtaskId} to a standalone task...`);

			// Find the highest task ID to determine the next ID
			const highestId = Math.max(...data.tasks.map((t) => t.id));
			const newTaskId = highestId + 1;

			// Create the new task from the subtask
			convertedTask = {
				id: newTaskId,
				title: removedSubtask.title,
				description: removedSubtask.description || '',
				details: removedSubtask.details || '',
				status: removedSubtask.status || 'pending',
				dependencies: removedSubtask.dependencies || [],
				priority: parentTask.priority || 'medium' // Inherit priority from parent
			};

			// Add the parent task as a dependency if not already present
			if (!convertedTask.dependencies.includes(parentId)) {
				convertedTask.dependencies.push(parentId);
			}

			// Add the converted task to the tasks array
			data.tasks.push(convertedTask);

			log('info', `Created new task ${newTaskId} from subtask ${subtaskId}`);
		} else {
			log('info', `Subtask ${subtaskId} deleted`);
		}

		// Write the updated tasks back to the file with proper context
		writeJSON(tasksPath, data, projectRoot, tag);

		// Generate task files if requested
		if (generateFiles) {
			log('info', 'Regenerating task files...');
			await generateTaskFiles(tasksPath, path.dirname(tasksPath), context);
		}

		return convertedTask;
	} catch (error) {
		log('error', `Error removing subtask: ${error.message}`);
		throw error;
	}
}

export default removeSubtask;

```

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

```javascript
/**
 * tools/index.js
 * Export all Task Master CLI tools for MCP server
 */

import { registerListTasksTool } from './get-tasks.js';
import logger from '../logger.js';
import { registerSetTaskStatusTool } from './set-task-status.js';
import { registerParsePRDTool } from './parse-prd.js';
import { registerUpdateTool } from './update.js';
import { registerUpdateTaskTool } from './update-task.js';
import { registerUpdateSubtaskTool } from './update-subtask.js';
import { registerGenerateTool } from './generate.js';
import { registerShowTaskTool } from './get-task.js';
import { registerNextTaskTool } from './next-task.js';
import { registerExpandTaskTool } from './expand-task.js';
import { registerAddTaskTool } from './add-task.js';
import { registerAddSubtaskTool } from './add-subtask.js';
import { registerRemoveSubtaskTool } from './remove-subtask.js';
import { registerAnalyzeProjectComplexityTool } from './analyze.js';
import { registerClearSubtasksTool } from './clear-subtasks.js';
import { registerExpandAllTool } from './expand-all.js';
import { registerRemoveDependencyTool } from './remove-dependency.js';
import { registerValidateDependenciesTool } from './validate-dependencies.js';
import { registerFixDependenciesTool } from './fix-dependencies.js';
import { registerComplexityReportTool } from './complexity-report.js';
import { registerAddDependencyTool } from './add-dependency.js';
import { registerRemoveTaskTool } from './remove-task.js';
import { registerInitializeProjectTool } from './initialize-project.js';
import { registerModelsTool } from './models.js';
import { registerMoveTaskTool } from './move-task.js';
import { registerResponseLanguageTool } from './response-language.js';
import { registerAddTagTool } from './add-tag.js';
import { registerDeleteTagTool } from './delete-tag.js';
import { registerListTagsTool } from './list-tags.js';
import { registerUseTagTool } from './use-tag.js';
import { registerRenameTagTool } from './rename-tag.js';
import { registerCopyTagTool } from './copy-tag.js';
import { registerResearchTool } from './research.js';
import { registerRulesTool } from './rules.js';
import { registerScopeUpTool } from './scope-up.js';
import { registerScopeDownTool } from './scope-down.js';

/**
 * Register all Task Master tools with the MCP server
 * @param {Object} server - FastMCP server instance
 */
export function registerTaskMasterTools(server) {
	try {
		// Register each tool in a logical workflow order

		// Group 1: Initialization & Setup
		registerInitializeProjectTool(server);
		registerModelsTool(server);
		registerRulesTool(server);
		registerParsePRDTool(server);

		// Group 2: Task Analysis & Expansion
		registerAnalyzeProjectComplexityTool(server);
		registerExpandTaskTool(server);
		registerExpandAllTool(server);
		registerScopeUpTool(server);
		registerScopeDownTool(server);

		// Group 3: Task Listing & Viewing
		registerListTasksTool(server);
		registerShowTaskTool(server);
		registerNextTaskTool(server);
		registerComplexityReportTool(server);

		// Group 4: Task Status & Management
		registerSetTaskStatusTool(server);
		registerGenerateTool(server);

		// Group 5: Task Creation & Modification
		registerAddTaskTool(server);
		registerAddSubtaskTool(server);
		registerUpdateTool(server);
		registerUpdateTaskTool(server);
		registerUpdateSubtaskTool(server);
		registerRemoveTaskTool(server);
		registerRemoveSubtaskTool(server);
		registerClearSubtasksTool(server);
		registerMoveTaskTool(server);

		// Group 6: Dependency Management
		registerAddDependencyTool(server);
		registerRemoveDependencyTool(server);
		registerValidateDependenciesTool(server);
		registerFixDependenciesTool(server);
		registerResponseLanguageTool(server);

		// Group 7: Tag Management
		registerListTagsTool(server);
		registerAddTagTool(server);
		registerDeleteTagTool(server);
		registerUseTagTool(server);
		registerRenameTagTool(server);
		registerCopyTagTool(server);

		// Group 8: Research Features
		registerResearchTool(server);
	} catch (error) {
		logger.error(`Error registering Task Master tools: ${error.message}`);
		throw error;
	}
}

export default {
	registerTaskMasterTools
};

```

--------------------------------------------------------------------------------
/docs/scripts/models-json-to-markdown.js:
--------------------------------------------------------------------------------

```javascript
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const supportedModelsPath = path.join(
	__dirname,
	'..',
	'modules',
	'supported-models.json'
);
const outputMarkdownPath = path.join(
	__dirname,
	'..',
	'..',
	'docs',
	'models.md'
);

function formatCost(cost) {
	if (cost === null || cost === undefined) {
		return '—';
	}
	return cost;
}

function formatSweScore(score) {
	if (score === null || score === undefined || score === 0) {
		return '—';
	}
	return score.toString();
}

function generateMarkdownTable(title, models) {
	if (!models || models.length === 0) {
		return `## ${title}\n\nNo models in this category.\n\n`;
	}
	let table = `## ${title}\n\n`;
	table += '| Provider | Model Name | SWE Score | Input Cost | Output Cost |\n';
	table += '|---|---|---|---|---|\n';
	models.forEach((model) => {
		table += `| ${model.provider} | ${model.modelName} | ${formatSweScore(model.sweScore)} | ${formatCost(model.inputCost)} | ${formatCost(model.outputCost)} |\n`;
	});
	table += '\n';
	return table;
}

function generateUnsupportedTable(models) {
	if (!models || models.length === 0) {
		return '## Unsupported Models\n\nNo unsupported models found.\n\n';
	}
	let table = '## Unsupported Models\n\n';
	table += '| Provider | Model Name | Reason |\n';
	table += '|---|---|---|\n';
	models.forEach((model) => {
		table += `| ${model.provider} | ${model.modelName} | ${model.reason || '—'} |\n`;
	});
	table += '\n';
	return table;
}

function main() {
	try {
		const correctSupportedModelsPath = path.join(
			__dirname,
			'..',
			'..',
			'scripts',
			'modules',
			'supported-models.json'
		);
		const correctOutputMarkdownPath = path.join(__dirname, '..', 'models.md');

		const supportedModelsContent = fs.readFileSync(
			correctSupportedModelsPath,
			'utf8'
		);
		const supportedModels = JSON.parse(supportedModelsContent);

		const mainModels = [];
		const researchModels = [];
		const fallbackModels = [];
		const unsupportedModels = [];

		for (const provider in supportedModels) {
			if (Object.hasOwnProperty.call(supportedModels, provider)) {
				const models = supportedModels[provider];
				models.forEach((model) => {
					const isSupported = model.supported !== false; // default to true if missing
					if (isSupported) {
						const modelEntry = {
							provider: provider,
							modelName: model.id,
							sweScore: model.swe_score,
							inputCost: model.cost_per_1m_tokens
								? model.cost_per_1m_tokens.input
								: null,
							outputCost: model.cost_per_1m_tokens
								? model.cost_per_1m_tokens.output
								: null
						};
						if (model.allowed_roles && model.allowed_roles.includes('main')) {
							mainModels.push(modelEntry);
						}
						if (
							model.allowed_roles &&
							model.allowed_roles.includes('research')
						) {
							researchModels.push(modelEntry);
						}
						if (
							model.allowed_roles &&
							model.allowed_roles.includes('fallback')
						) {
							fallbackModels.push(modelEntry);
						}
					} else {
						unsupportedModels.push({
							provider: provider,
							modelName: model.id,
							reason: model.reason || 'Not specified'
						});
					}
				});
			}
		}

		const date = new Date();
		const monthNames = [
			'January',
			'February',
			'March',
			'April',
			'May',
			'June',
			'July',
			'August',
			'September',
			'October',
			'November',
			'December'
		];
		const formattedDate = `${monthNames[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;

		let markdownContent = `# Available Models as of ${formattedDate}\n\n`;
		markdownContent += generateMarkdownTable('Main Models', mainModels);
		markdownContent += generateMarkdownTable('Research Models', researchModels);
		markdownContent += generateMarkdownTable('Fallback Models', fallbackModels);
		markdownContent += generateUnsupportedTable(unsupportedModels);

		fs.writeFileSync(correctOutputMarkdownPath, markdownContent, 'utf8');
		console.log(`Successfully updated ${correctOutputMarkdownPath}`);
	} catch (error) {
		console.error('Error transforming models.json to models.md:', error);
		process.exit(1);
	}
}

main();

```

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

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

// Mock external modules
jest.mock('child_process', () => ({
	execSync: jest.fn()
}));

// Mock console methods
jest.mock('console', () => ({
	log: jest.fn(),
	info: jest.fn(),
	warn: jest.fn(),
	error: jest.fn(),
	clear: jest.fn()
}));

describe('Kiro Integration', () => {
	let tempDir;

	beforeEach(() => {
		jest.clearAllMocks();

		// Create a temporary directory for testing
		tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'task-master-test-'));

		// Spy on fs methods
		jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
		jest.spyOn(fs, 'readFileSync').mockImplementation((filePath) => {
			if (filePath.toString().includes('mcp.json')) {
				return JSON.stringify({ mcpServers: {} }, null, 2);
			}
			return '{}';
		});
		jest.spyOn(fs, 'existsSync').mockImplementation(() => false);
		jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {});
	});

	afterEach(() => {
		// Clean up the temporary directory
		try {
			fs.rmSync(tempDir, { recursive: true, force: true });
		} catch (err) {
			console.error(`Error cleaning up: ${err.message}`);
		}
	});

	// Test function that simulates the createProjectStructure behavior for Kiro files
	function mockCreateKiroStructure() {
		// This function simulates the actual kiro profile creation logic
		// It explicitly calls the mocked fs methods to ensure consistency with the test environment

		// Simulate directory creation calls - these will call the mocked mkdirSync
		fs.mkdirSync(path.join(tempDir, '.kiro'), { recursive: true });
		fs.mkdirSync(path.join(tempDir, '.kiro', 'steering'), { recursive: true });
		fs.mkdirSync(path.join(tempDir, '.kiro', 'settings'), { recursive: true });

		// Create MCP config file at .kiro/settings/mcp.json
		// This will call the mocked writeFileSync
		fs.writeFileSync(
			path.join(tempDir, '.kiro', 'settings', 'mcp.json'),
			JSON.stringify({ mcpServers: {} }, null, 2)
		);

		// Create kiro rule files in steering directory
		// All these will call the mocked writeFileSync
		fs.writeFileSync(
			path.join(tempDir, '.kiro', 'steering', 'kiro_rules.md'),
			'# Kiro Rules\n\nKiro-specific rules and instructions.'
		);
		fs.writeFileSync(
			path.join(tempDir, '.kiro', 'steering', 'dev_workflow.md'),
			'# Development Workflow\n\nDevelopment workflow instructions.'
		);
		fs.writeFileSync(
			path.join(tempDir, '.kiro', 'steering', 'self_improve.md'),
			'# Self Improvement\n\nSelf improvement guidelines.'
		);
		fs.writeFileSync(
			path.join(tempDir, '.kiro', 'steering', 'taskmaster.md'),
			'# Task Master\n\nTask Master integration instructions.'
		);
	}

	test('creates all required .kiro directories', () => {
		// Act
		mockCreateKiroStructure();

		// Assert
		expect(fs.mkdirSync).toHaveBeenCalledWith(path.join(tempDir, '.kiro'), {
			recursive: true
		});
		expect(fs.mkdirSync).toHaveBeenCalledWith(
			path.join(tempDir, '.kiro', 'steering'),
			{
				recursive: true
			}
		);
		expect(fs.mkdirSync).toHaveBeenCalledWith(
			path.join(tempDir, '.kiro', 'settings'),
			{
				recursive: true
			}
		);
	});

	test('creates Kiro mcp.json with mcpServers format', () => {
		// Act
		mockCreateKiroStructure();

		// Assert
		expect(fs.writeFileSync).toHaveBeenCalledWith(
			path.join(tempDir, '.kiro', 'settings', 'mcp.json'),
			JSON.stringify({ mcpServers: {} }, null, 2)
		);
	});

	test('creates rule files in steering directory', () => {
		// Act
		mockCreateKiroStructure();

		// Assert
		expect(fs.writeFileSync).toHaveBeenCalledWith(
			path.join(tempDir, '.kiro', 'steering', 'kiro_rules.md'),
			'# Kiro Rules\n\nKiro-specific rules and instructions.'
		);
		expect(fs.writeFileSync).toHaveBeenCalledWith(
			path.join(tempDir, '.kiro', 'steering', 'dev_workflow.md'),
			'# Development Workflow\n\nDevelopment workflow instructions.'
		);
		expect(fs.writeFileSync).toHaveBeenCalledWith(
			path.join(tempDir, '.kiro', 'steering', 'self_improve.md'),
			'# Self Improvement\n\nSelf improvement guidelines.'
		);
		expect(fs.writeFileSync).toHaveBeenCalledWith(
			path.join(tempDir, '.kiro', 'steering', 'taskmaster.md'),
			'# Task Master\n\nTask Master integration instructions.'
		);
	});
});

```

--------------------------------------------------------------------------------
/.claude/commands/tm/tm-main.md:
--------------------------------------------------------------------------------

```markdown
# Task Master Command Reference

Comprehensive command structure for Task Master integration with Claude Code.

## Command Organization

Commands are organized hierarchically to match Task Master's CLI structure while providing enhanced Claude Code integration.

## Project Setup & Configuration

### `/project:tm/init`
- `init-project` - Initialize new project (handles PRD files intelligently)
- `init-project-quick` - Quick setup with auto-confirmation (-y flag)

### `/project:tm/models`
- `view-models` - View current AI model configuration
- `setup-models` - Interactive model configuration
- `set-main` - Set primary generation model
- `set-research` - Set research model
- `set-fallback` - Set fallback model

## Task Generation

### `/project:tm/parse-prd`
- `parse-prd` - Generate tasks from PRD document
- `parse-prd-with-research` - Enhanced parsing with research mode

### `/project:tm/generate`
- `generate-tasks` - Create individual task files from tasks.json

## Task Management

### `/project:tm/list`
- `list-tasks` - Smart listing with natural language filters
- `list-tasks-with-subtasks` - Include subtasks in hierarchical view
- `list-tasks-by-status` - Filter by specific status

### `/project:tm/set-status`
- `to-pending` - Reset task to pending
- `to-in-progress` - Start working on task
- `to-done` - Mark task complete
- `to-review` - Submit for review
- `to-deferred` - Defer task
- `to-cancelled` - Cancel task

### `/project:tm/sync-readme`
- `sync-readme` - Export tasks to README.md with formatting

### `/project:tm/update`
- `update-task` - Update tasks with natural language
- `update-tasks-from-id` - Update multiple tasks from a starting point
- `update-single-task` - Update specific task

### `/project:tm/add-task`
- `add-task` - Add new task with AI assistance

### `/project:tm/remove-task`
- `remove-task` - Remove task with confirmation

## Subtask Management

### `/project:tm/add-subtask`
- `add-subtask` - Add new subtask to parent
- `convert-task-to-subtask` - Convert existing task to subtask

### `/project:tm/remove-subtask`
- `remove-subtask` - Remove subtask (with optional conversion)

### `/project:tm/clear-subtasks`
- `clear-subtasks` - Clear subtasks from specific task
- `clear-all-subtasks` - Clear all subtasks globally

## Task Analysis & Breakdown

### `/project:tm/analyze-complexity`
- `analyze-complexity` - Analyze and generate expansion recommendations

### `/project:tm/complexity-report`
- `complexity-report` - Display complexity analysis report

### `/project:tm/expand`
- `expand-task` - Break down specific task
- `expand-all-tasks` - Expand all eligible tasks
- `with-research` - Enhanced expansion

## Task Navigation

### `/project:tm/next`
- `next-task` - Intelligent next task recommendation

### `/project:tm/show`
- `show-task` - Display detailed task information

### `/project:tm/status`
- `project-status` - Comprehensive project dashboard

## Dependency Management

### `/project:tm/add-dependency`
- `add-dependency` - Add task dependency

### `/project:tm/remove-dependency`
- `remove-dependency` - Remove task dependency

### `/project:tm/validate-dependencies`
- `validate-dependencies` - Check for dependency issues

### `/project:tm/fix-dependencies`
- `fix-dependencies` - Automatically fix dependency problems

## Workflows & Automation

### `/project:tm/workflows`
- `smart-workflow` - Context-aware intelligent workflow execution
- `command-pipeline` - Chain multiple commands together
- `auto-implement-tasks` - Advanced auto-implementation with code generation

## Utilities

### `/project:tm/utils`
- `analyze-project` - Deep project analysis and insights

### `/project:tm/setup`
- `install-taskmaster` - Comprehensive installation guide
- `quick-install-taskmaster` - One-line global installation

## Usage Patterns

### Natural Language
Most commands accept natural language arguments:
```
/project:tm/add-task create user authentication system
/project:tm/update mark all API tasks as high priority
/project:tm/list show blocked tasks
```

### ID-Based Commands
Commands requiring IDs intelligently parse from $ARGUMENTS:
```
/project:tm/show 45
/project:tm/expand 23
/project:tm/set-status/to-done 67
```

### Smart Defaults
Commands provide intelligent defaults and suggestions based on context.
```

--------------------------------------------------------------------------------
/assets/claude/commands/tm/tm-main.md:
--------------------------------------------------------------------------------

```markdown
# Task Master Command Reference

Comprehensive command structure for Task Master integration with Claude Code.

## Command Organization

Commands are organized hierarchically to match Task Master's CLI structure while providing enhanced Claude Code integration.

## Project Setup & Configuration

### `/project:tm/init`
- `init-project` - Initialize new project (handles PRD files intelligently)
- `init-project-quick` - Quick setup with auto-confirmation (-y flag)

### `/project:tm/models`
- `view-models` - View current AI model configuration
- `setup-models` - Interactive model configuration
- `set-main` - Set primary generation model
- `set-research` - Set research model
- `set-fallback` - Set fallback model

## Task Generation

### `/project:tm/parse-prd`
- `parse-prd` - Generate tasks from PRD document
- `parse-prd-with-research` - Enhanced parsing with research mode

### `/project:tm/generate`
- `generate-tasks` - Create individual task files from tasks.json

## Task Management

### `/project:tm/list`
- `list-tasks` - Smart listing with natural language filters
- `list-tasks-with-subtasks` - Include subtasks in hierarchical view
- `list-tasks-by-status` - Filter by specific status

### `/project:tm/set-status`
- `to-pending` - Reset task to pending
- `to-in-progress` - Start working on task
- `to-done` - Mark task complete
- `to-review` - Submit for review
- `to-deferred` - Defer task
- `to-cancelled` - Cancel task

### `/project:tm/sync-readme`
- `sync-readme` - Export tasks to README.md with formatting

### `/project:tm/update`
- `update-task` - Update tasks with natural language
- `update-tasks-from-id` - Update multiple tasks from a starting point
- `update-single-task` - Update specific task

### `/project:tm/add-task`
- `add-task` - Add new task with AI assistance

### `/project:tm/remove-task`
- `remove-task` - Remove task with confirmation

## Subtask Management

### `/project:tm/add-subtask`
- `add-subtask` - Add new subtask to parent
- `convert-task-to-subtask` - Convert existing task to subtask

### `/project:tm/remove-subtask`
- `remove-subtask` - Remove subtask (with optional conversion)

### `/project:tm/clear-subtasks`
- `clear-subtasks` - Clear subtasks from specific task
- `clear-all-subtasks` - Clear all subtasks globally

## Task Analysis & Breakdown

### `/project:tm/analyze-complexity`
- `analyze-complexity` - Analyze and generate expansion recommendations

### `/project:tm/complexity-report`
- `complexity-report` - Display complexity analysis report

### `/project:tm/expand`
- `expand-task` - Break down specific task
- `expand-all-tasks` - Expand all eligible tasks
- `with-research` - Enhanced expansion

## Task Navigation

### `/project:tm/next`
- `next-task` - Intelligent next task recommendation

### `/project:tm/show`
- `show-task` - Display detailed task information

### `/project:tm/status`
- `project-status` - Comprehensive project dashboard

## Dependency Management

### `/project:tm/add-dependency`
- `add-dependency` - Add task dependency

### `/project:tm/remove-dependency`
- `remove-dependency` - Remove task dependency

### `/project:tm/validate-dependencies`
- `validate-dependencies` - Check for dependency issues

### `/project:tm/fix-dependencies`
- `fix-dependencies` - Automatically fix dependency problems

## Workflows & Automation

### `/project:tm/workflows`
- `smart-workflow` - Context-aware intelligent workflow execution
- `command-pipeline` - Chain multiple commands together
- `auto-implement-tasks` - Advanced auto-implementation with code generation

## Utilities

### `/project:tm/utils`
- `analyze-project` - Deep project analysis and insights

### `/project:tm/setup`
- `install-taskmaster` - Comprehensive installation guide
- `quick-install-taskmaster` - One-line global installation

## Usage Patterns

### Natural Language
Most commands accept natural language arguments:
```
/project:tm/add-task create user authentication system
/project:tm/update mark all API tasks as high priority
/project:tm/list show blocked tasks
```

### ID-Based Commands
Commands requiring IDs intelligently parse from $ARGUMENTS:
```
/project:tm/show 45
/project:tm/expand 23
/project:tm/set-status/to-done 67
```

### Smart Defaults
Commands provide intelligent defaults and suggestions based on context.
```

--------------------------------------------------------------------------------
/mcp-server/src/core/direct-functions/create-tag-from-branch.js:
--------------------------------------------------------------------------------

```javascript
/**
 * create-tag-from-branch.js
 * Direct function implementation for creating tags from git branches
 */

import { createTagFromBranch } from '../../../../scripts/modules/task-manager/tag-management.js';
import {
	getCurrentBranch,
	isGitRepository
} from '../../../../scripts/modules/utils/git-utils.js';
import {
	enableSilentMode,
	disableSilentMode
} from '../../../../scripts/modules/utils.js';
import { createLogWrapper } from '../../tools/utils.js';

/**
 * Direct function wrapper for creating tags from git branches with error handling.
 *
 * @param {Object} args - Command arguments
 * @param {string} args.tasksJsonPath - Path to the tasks.json file (resolved by tool)
 * @param {string} [args.branchName] - Git branch name (optional, uses current branch if not provided)
 * @param {boolean} [args.copyFromCurrent] - Copy tasks from current tag
 * @param {string} [args.copyFromTag] - Copy tasks from specific tag
 * @param {string} [args.description] - Custom description for the tag
 * @param {boolean} [args.autoSwitch] - Automatically switch to the new tag
 * @param {string} [args.projectRoot] - Project root path
 * @param {Object} log - Logger object
 * @param {Object} context - Additional context (session)
 * @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string } }
 */
export async function createTagFromBranchDirect(args, log, context = {}) {
	// Destructure expected args
	const {
		tasksJsonPath,
		branchName,
		copyFromCurrent,
		copyFromTag,
		description,
		autoSwitch,
		projectRoot
	} = args;
	const { session } = context;

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

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

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

		// Check if projectRoot was provided
		if (!projectRoot) {
			log.error('createTagFromBranchDirect called without projectRoot');
			disableSilentMode();
			return {
				success: false,
				error: {
					code: 'MISSING_ARGUMENT',
					message: 'projectRoot is required'
				}
			};
		}

		// Check if we're in a git repository
		if (!(await isGitRepository(projectRoot))) {
			log.error('Not in a git repository');
			disableSilentMode();
			return {
				success: false,
				error: {
					code: 'NOT_GIT_REPOSITORY',
					message: 'Not in a git repository. Cannot create tag from branch.'
				}
			};
		}

		// Determine branch name
		let targetBranch = branchName;
		if (!targetBranch) {
			targetBranch = await getCurrentBranch(projectRoot);
			if (!targetBranch) {
				log.error('Could not determine current git branch');
				disableSilentMode();
				return {
					success: false,
					error: {
						code: 'NO_CURRENT_BRANCH',
						message: 'Could not determine current git branch'
					}
				};
			}
		}

		log.info(`Creating tag from git branch: ${targetBranch}`);

		// Prepare options
		const options = {
			copyFromCurrent: copyFromCurrent || false,
			copyFromTag,
			description:
				description || `Tag created from git branch "${targetBranch}"`,
			autoSwitch: autoSwitch || false
		};

		// Call the createTagFromBranch function
		const result = await createTagFromBranch(
			tasksJsonPath,
			targetBranch,
			options,
			{
				session,
				mcpLog,
				projectRoot
			},
			'json' // outputFormat - use 'json' to suppress CLI UI
		);

		// Restore normal logging
		disableSilentMode();

		return {
			success: true,
			data: {
				branchName: result.branchName,
				tagName: result.tagName,
				created: result.created,
				mappingUpdated: result.mappingUpdated,
				autoSwitched: result.autoSwitched,
				message: `Successfully created tag "${result.tagName}" from branch "${result.branchName}"`
			}
		};
	} catch (error) {
		// Make sure to restore normal logging even if there's an error
		disableSilentMode();

		log.error(`Error in createTagFromBranchDirect: ${error.message}`);
		return {
			success: false,
			error: {
				code: error.code || 'CREATE_TAG_FROM_BRANCH_ERROR',
				message: error.message
			}
		};
	}
}

```

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

```javascript
/**
 * Direct function wrapper for addSubtask
 */

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

/**
 * Add a subtask to an existing task
 * @param {Object} args - Function arguments
 * @param {string} args.tasksJsonPath - Explicit path to the tasks.json file.
 * @param {string} args.id - Parent task ID
 * @param {string} [args.taskId] - Existing task ID to convert to subtask (optional)
 * @param {string} [args.title] - Title for new subtask (when creating a new subtask)
 * @param {string} [args.description] - Description for new subtask
 * @param {string} [args.details] - Implementation details for new subtask
 * @param {string} [args.status] - Status for new subtask (default: 'pending')
 * @param {string} [args.dependencies] - Comma-separated list of dependency IDs
 * @param {boolean} [args.skipGenerate] - Skip regenerating task files
 * @param {string} [args.projectRoot] - Project root directory
 * @param {string} [args.tag] - Tag for the task
 * @param {Object} log - Logger object
 * @returns {Promise<{success: boolean, data?: Object, error?: string}>}
 */
export async function addSubtaskDirect(args, log) {
	// Destructure expected args
	const {
		tasksJsonPath,
		id,
		taskId,
		title,
		description,
		details,
		status,
		dependencies: dependenciesStr,
		skipGenerate,
		projectRoot,
		tag
	} = args;
	try {
		log.info(`Adding subtask with args: ${JSON.stringify(args)}`);

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

		if (!id) {
			return {
				success: false,
				error: {
					code: 'INPUT_VALIDATION_ERROR',
					message: 'Parent task ID is required'
				}
			};
		}

		// Either taskId or title must be provided
		if (!taskId && !title) {
			return {
				success: false,
				error: {
					code: 'INPUT_VALIDATION_ERROR',
					message: 'Either taskId or title must be provided'
				}
			};
		}

		// Use provided path
		const tasksPath = tasksJsonPath;

		// Parse dependencies if provided
		let dependencies = [];
		if (dependenciesStr) {
			dependencies = dependenciesStr.split(',').map((depId) => {
				// Handle both regular IDs and dot notation
				return depId.includes('.') ? depId.trim() : parseInt(depId.trim(), 10);
			});
		}

		// Convert existingTaskId to a number if provided
		const existingTaskId = taskId ? parseInt(taskId, 10) : null;

		// Convert parent ID to a number
		const parentId = parseInt(id, 10);

		// Determine if we should generate files
		const generateFiles = !skipGenerate;

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

		const context = { projectRoot, tag };

		// Case 1: Convert existing task to subtask
		if (existingTaskId) {
			log.info(`Converting task ${existingTaskId} to a subtask of ${parentId}`);
			const result = await addSubtask(
				tasksPath,
				parentId,
				existingTaskId,
				null,
				generateFiles,
				context
			);

			// Restore normal logging
			disableSilentMode();

			return {
				success: true,
				data: {
					message: `Task ${existingTaskId} successfully converted to a subtask of task ${parentId}`,
					subtask: result
				}
			};
		}
		// Case 2: Create new subtask
		else {
			log.info(`Creating new subtask for parent task ${parentId}`);

			const newSubtaskData = {
				title: title,
				description: description || '',
				details: details || '',
				status: status || 'pending',
				dependencies: dependencies
			};

			const result = await addSubtask(
				tasksPath,
				parentId,
				null,
				newSubtaskData,
				generateFiles,
				context
			);

			// Restore normal logging
			disableSilentMode();

			return {
				success: true,
				data: {
					message: `New subtask ${parentId}.${result.id} successfully created`,
					subtask: result
				}
			};
		}
	} catch (error) {
		// Make sure to restore normal logging even if there's an error
		disableSilentMode();

		log.error(`Error in addSubtaskDirect: ${error.message}`);
		return {
			success: false,
			error: {
				code: 'CORE_FUNCTION_ERROR',
				message: error.message
			}
		};
	}
}

```

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

```javascript
/**
 * show-task.js
 * Direct function implementation for showing task details
 */

import {
	findTaskById,
	readComplexityReport,
	readJSON
} from '../../../../scripts/modules/utils.js';
import { findTasksPath } from '../utils/path-utils.js';

/**
 * Direct function wrapper for getting task details.
 *
 * @param {Object} args - Command arguments.
 * @param {string} args.id - Task ID to show.
 * @param {string} [args.file] - Optional path to the tasks file (passed to findTasksPath).
 * @param {string} args.reportPath - Explicit path to the complexity report file.
 * @param {string} [args.status] - Optional status to filter subtasks by.
 * @param {string} args.projectRoot - Absolute path to the project root directory (already normalized by tool).
 * @param {string} [args.tag] - Tag for the task
 * @param {Object} log - Logger object.
 * @param {Object} context - Context object containing session data.
 * @returns {Promise<Object>} - Result object with success status and data/error information.
 */
export async function showTaskDirect(args, log) {
	// This function doesn't need session context since it only reads data
	// Destructure projectRoot and other args. projectRoot is assumed normalized.
	const { id, file, reportPath, status, projectRoot, tag } = args;

	log.info(
		`Showing task direct function. ID: ${id}, File: ${file}, Status Filter: ${status}, ProjectRoot: ${projectRoot}`
	);

	// --- Path Resolution using the passed (already normalized) projectRoot ---
	let tasksJsonPath;
	try {
		// Use the projectRoot passed directly from args
		tasksJsonPath = findTasksPath(
			{ projectRoot: projectRoot, file: file },
			log
		);
		log.info(`Resolved tasks path: ${tasksJsonPath}`);
	} catch (error) {
		log.error(`Error finding tasks.json: ${error.message}`);
		return {
			success: false,
			error: {
				code: 'TASKS_FILE_NOT_FOUND',
				message: `Failed to find tasks.json: ${error.message}`
			}
		};
	}
	// --- End Path Resolution ---

	// --- Rest of the function remains the same, using tasksJsonPath ---
	try {
		const tasksData = readJSON(tasksJsonPath, projectRoot, tag);
		if (!tasksData || !tasksData.tasks) {
			return {
				success: false,
				error: { code: 'INVALID_TASKS_DATA', message: 'Invalid tasks data' }
			};
		}

		const complexityReport = readComplexityReport(reportPath);

		// Parse comma-separated IDs
		const taskIds = id
			.split(',')
			.map((taskId) => taskId.trim())
			.filter((taskId) => taskId.length > 0);

		if (taskIds.length === 0) {
			return {
				success: false,
				error: {
					code: 'INVALID_TASK_ID',
					message: 'No valid task IDs provided'
				}
			};
		}

		// Handle single task ID (existing behavior)
		if (taskIds.length === 1) {
			const { task, originalSubtaskCount } = findTaskById(
				tasksData.tasks,
				taskIds[0],
				complexityReport,
				status
			);

			if (!task) {
				return {
					success: false,
					error: {
						code: 'TASK_NOT_FOUND',
						message: `Task or subtask with ID ${taskIds[0]} not found`
					}
				};
			}

			log.info(`Successfully retrieved task ${taskIds[0]}.`);

			const returnData = { ...task };
			if (originalSubtaskCount !== null) {
				returnData._originalSubtaskCount = originalSubtaskCount;
				returnData._subtaskFilter = status;
			}

			return { success: true, data: returnData };
		}

		// Handle multiple task IDs
		const foundTasks = [];
		const notFoundIds = [];

		taskIds.forEach((taskId) => {
			const { task, originalSubtaskCount } = findTaskById(
				tasksData.tasks,
				taskId,
				complexityReport,
				status
			);

			if (task) {
				const taskData = { ...task };
				if (originalSubtaskCount !== null) {
					taskData._originalSubtaskCount = originalSubtaskCount;
					taskData._subtaskFilter = status;
				}
				foundTasks.push(taskData);
			} else {
				notFoundIds.push(taskId);
			}
		});

		log.info(
			`Successfully retrieved ${foundTasks.length} of ${taskIds.length} requested tasks.`
		);

		// Return multiple tasks with metadata
		return {
			success: true,
			data: {
				tasks: foundTasks,
				requestedIds: taskIds,
				foundCount: foundTasks.length,
				notFoundIds: notFoundIds,
				isMultiple: true
			}
		};
	} catch (error) {
		log.error(`Error showing task ${id}: ${error.message}`);
		return {
			success: false,
			error: {
				code: 'TASK_OPERATION_ERROR',
				message: error.message
			}
		};
	}
}

```

--------------------------------------------------------------------------------
/mcp-server/src/core/context-manager.js:
--------------------------------------------------------------------------------

```javascript
/**
 * context-manager.js
 * Context and cache management for Task Master MCP Server
 */

import { FastMCP } from 'fastmcp';
import { LRUCache } from 'lru-cache';

/**
 * Configuration options for the ContextManager
 * @typedef {Object} ContextManagerConfig
 * @property {number} maxCacheSize - Maximum number of items in the cache
 * @property {number} ttl - Time to live for cached items in milliseconds
 * @property {number} maxContextSize - Maximum size of context window in tokens
 */

export class ContextManager {
	/**
	 * Create a new ContextManager instance
	 * @param {ContextManagerConfig} config - Configuration options
	 */
	constructor(config = {}) {
		this.config = {
			maxCacheSize: config.maxCacheSize || 1000,
			ttl: config.ttl || 1000 * 60 * 5, // 5 minutes default
			maxContextSize: config.maxContextSize || 4000
		};

		// Initialize LRU cache for context data
		this.cache = new LRUCache({
			max: this.config.maxCacheSize,
			ttl: this.config.ttl,
			updateAgeOnGet: true
		});

		// Cache statistics
		this.stats = {
			hits: 0,
			misses: 0,
			invalidations: 0
		};
	}

	/**
	 * Create a new context or retrieve from cache
	 * @param {string} contextId - Unique identifier for the context
	 * @param {Object} metadata - Additional metadata for the context
	 * @returns {Object} Context object with metadata
	 */
	async getContext(contextId, metadata = {}) {
		const cacheKey = this._getCacheKey(contextId, metadata);

		// Try to get from cache first
		const cached = this.cache.get(cacheKey);
		if (cached) {
			this.stats.hits++;
			return cached;
		}

		this.stats.misses++;

		// Create new context if not in cache
		const context = {
			id: contextId,
			metadata: {
				...metadata,
				created: new Date().toISOString()
			}
		};

		// Cache the new context
		this.cache.set(cacheKey, context);

		return context;
	}

	/**
	 * Update an existing context
	 * @param {string} contextId - Context identifier
	 * @param {Object} updates - Updates to apply to the context
	 * @returns {Object} Updated context
	 */
	async updateContext(contextId, updates) {
		const context = await this.getContext(contextId);

		// Apply updates to context
		Object.assign(context.metadata, updates);

		// Update cache
		const cacheKey = this._getCacheKey(contextId, context.metadata);
		this.cache.set(cacheKey, context);

		return context;
	}

	/**
	 * Invalidate a context in the cache
	 * @param {string} contextId - Context identifier
	 * @param {Object} metadata - Metadata used in the cache key
	 */
	invalidateContext(contextId, metadata = {}) {
		const cacheKey = this._getCacheKey(contextId, metadata);
		this.cache.delete(cacheKey);
		this.stats.invalidations++;
	}

	/**
	 * Get cached data associated with a specific key.
	 * Increments cache hit stats if found.
	 * @param {string} key - The cache key.
	 * @returns {any | undefined} The cached data or undefined if not found/expired.
	 */
	getCachedData(key) {
		const cached = this.cache.get(key);
		if (cached !== undefined) {
			// Check for undefined specifically, as null/false might be valid cached values
			this.stats.hits++;
			return cached;
		}
		this.stats.misses++;
		return undefined;
	}

	/**
	 * Set data in the cache with a specific key.
	 * @param {string} key - The cache key.
	 * @param {any} data - The data to cache.
	 */
	setCachedData(key, data) {
		this.cache.set(key, data);
	}

	/**
	 * Invalidate a specific cache key.
	 * Increments invalidation stats.
	 * @param {string} key - The cache key to invalidate.
	 */
	invalidateCacheKey(key) {
		this.cache.delete(key);
		this.stats.invalidations++;
	}

	/**
	 * Get cache statistics
	 * @returns {Object} Cache statistics
	 */
	getStats() {
		return {
			hits: this.stats.hits,
			misses: this.stats.misses,
			invalidations: this.stats.invalidations,
			size: this.cache.size,
			maxSize: this.config.maxCacheSize,
			ttl: this.config.ttl
		};
	}

	/**
	 * Generate a cache key from context ID and metadata
	 * @private
	 * @deprecated No longer used for direct cache key generation outside the manager.
	 *             Prefer generating specific keys in calling functions.
	 */
	_getCacheKey(contextId, metadata) {
		// Kept for potential backward compatibility or internal use if needed later.
		return `${contextId}:${JSON.stringify(metadata)}`;
	}
}

// Export a singleton instance with default config
export const contextManager = new ContextManager();

```

--------------------------------------------------------------------------------
/.github/scripts/parse-metrics.mjs:
--------------------------------------------------------------------------------

```
#!/usr/bin/env node

import { readFileSync, existsSync, writeFileSync } from 'fs';

function parseMetricsTable(content, metricName) {
	const lines = content.split('\n');

	for (let i = 0; i < lines.length; i++) {
		const line = lines[i].trim();
		// Match a markdown table row like: | Metric Name | value | ...
		const safeName = metricName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
		const re = new RegExp(`^\\|\\s*${safeName}\\s*\\|\\s*([^|]+)\\|?`);
		const match = line.match(re);
		if (match) {
			return match[1].trim() || 'N/A';
		}
	}
	return 'N/A';
}

function parseCountMetric(content, metricName) {
	const result = parseMetricsTable(content, metricName);
	// Extract number from string, handling commas and spaces
	const numberMatch = result.toString().match(/[\d,]+/);
	if (numberMatch) {
		const number = parseInt(numberMatch[0].replace(/,/g, ''));
		return isNaN(number) ? 0 : number;
	}
	return 0;
}

function main() {
	const metrics = {
		issues_created: 0,
		issues_closed: 0,
		prs_created: 0,
		prs_merged: 0,
		issue_avg_first_response: 'N/A',
		issue_avg_time_to_close: 'N/A',
		pr_avg_first_response: 'N/A',
		pr_avg_merge_time: 'N/A'
	};

	// Parse issue metrics
	if (existsSync('issue_metrics.md')) {
		console.log('📄 Found issue_metrics.md, parsing...');
		const issueContent = readFileSync('issue_metrics.md', 'utf8');

		metrics.issues_created = parseCountMetric(
			issueContent,
			'Total number of items created'
		);
		metrics.issues_closed = parseCountMetric(
			issueContent,
			'Number of items closed'
		);
		metrics.issue_avg_first_response = parseMetricsTable(
			issueContent,
			'Time to first response'
		);
		metrics.issue_avg_time_to_close = parseMetricsTable(
			issueContent,
			'Time to close'
		);
	} else {
		console.warn('[parse-metrics] issue_metrics.md not found; using defaults.');
	}

	// Parse PR created metrics
	if (existsSync('pr_created_metrics.md')) {
		console.log('📄 Found pr_created_metrics.md, parsing...');
		const prCreatedContent = readFileSync('pr_created_metrics.md', 'utf8');

		metrics.prs_created = parseCountMetric(
			prCreatedContent,
			'Total number of items created'
		);
		metrics.pr_avg_first_response = parseMetricsTable(
			prCreatedContent,
			'Time to first response'
		);
	} else {
		console.warn(
			'[parse-metrics] pr_created_metrics.md not found; using defaults.'
		);
	}

	// Parse PR merged metrics (for more accurate merge data)
	if (existsSync('pr_merged_metrics.md')) {
		console.log('📄 Found pr_merged_metrics.md, parsing...');
		const prMergedContent = readFileSync('pr_merged_metrics.md', 'utf8');

		metrics.prs_merged = parseCountMetric(
			prMergedContent,
			'Total number of items created'
		);
		// For merged PRs, "Time to close" is actually time to merge
		metrics.pr_avg_merge_time = parseMetricsTable(
			prMergedContent,
			'Time to close'
		);
	} else {
		console.warn(
			'[parse-metrics] pr_merged_metrics.md not found; falling back to pr_metrics.md.'
		);
		// Fallback: try old pr_metrics.md if it exists
		if (existsSync('pr_metrics.md')) {
			console.log('📄 Falling back to pr_metrics.md...');
			const prContent = readFileSync('pr_metrics.md', 'utf8');

			const mergedCount = parseCountMetric(prContent, 'Number of items merged');
			metrics.prs_merged =
				mergedCount || parseCountMetric(prContent, 'Number of items closed');

			const maybeMergeTime = parseMetricsTable(
				prContent,
				'Average time to merge'
			);
			metrics.pr_avg_merge_time =
				maybeMergeTime !== 'N/A'
					? maybeMergeTime
					: parseMetricsTable(prContent, 'Time to close');
		} else {
			console.warn('[parse-metrics] pr_metrics.md not found; using defaults.');
		}
	}

	// Output for GitHub Actions
	const output = Object.entries(metrics)
		.map(([key, value]) => `${key}=${value}`)
		.join('\n');

	// Always output to stdout for debugging
	console.log('\n=== FINAL METRICS ===');
	Object.entries(metrics).forEach(([key, value]) => {
		console.log(`${key}: ${value}`);
	});

	// Write to GITHUB_OUTPUT if in GitHub Actions
	if (process.env.GITHUB_OUTPUT) {
		try {
			writeFileSync(process.env.GITHUB_OUTPUT, output + '\n', { flag: 'a' });
			console.log(
				`\nSuccessfully wrote metrics to ${process.env.GITHUB_OUTPUT}`
			);
		} catch (error) {
			console.error(`Failed to write to GITHUB_OUTPUT: ${error.message}`);
			process.exit(1);
		}
	} else {
		console.log(
			'\nNo GITHUB_OUTPUT environment variable found, skipping file write'
		);
	}
}

main();

```

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

```typescript
/**
 * Toast Notification Component
 */

import React, { useState, useEffect } from 'react';
import type { ToastNotification as ToastType } from '../types';

interface ToastNotificationProps {
	notification: ToastType;
	onDismiss: (id: string) => void;
}

export const ToastNotification: React.FC<ToastNotificationProps> = ({
	notification,
	onDismiss
}) => {
	const [isVisible, setIsVisible] = useState(true);
	const [progress, setProgress] = useState(100);
	const duration = notification.duration || 5000; // 5 seconds default

	useEffect(() => {
		const progressInterval = setInterval(() => {
			setProgress((prev) => {
				const decrease = (100 / duration) * 100; // Update every 100ms
				return Math.max(0, prev - decrease);
			});
		}, 100);

		const timeoutId = setTimeout(() => {
			setIsVisible(false);
			setTimeout(() => onDismiss(notification.id), 300); // Wait for animation
		}, duration);

		return () => {
			clearInterval(progressInterval);
			clearTimeout(timeoutId);
		};
	}, [notification.id, duration, onDismiss]);

	const getIcon = () => {
		switch (notification.type) {
			case 'success':
				return (
					<svg
						className="w-5 h-5 text-green-400"
						fill="none"
						stroke="currentColor"
						viewBox="0 0 24 24"
					>
						<path
							strokeLinecap="round"
							strokeLinejoin="round"
							strokeWidth={2}
							d="M5 13l4 4L19 7"
						/>
					</svg>
				);
			case 'info':
				return (
					<svg
						className="w-5 h-5 text-blue-400"
						fill="none"
						stroke="currentColor"
						viewBox="0 0 24 24"
					>
						<path
							strokeLinecap="round"
							strokeLinejoin="round"
							strokeWidth={2}
							d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
						/>
					</svg>
				);
			case 'warning':
				return (
					<svg
						className="w-5 h-5 text-yellow-400"
						fill="none"
						stroke="currentColor"
						viewBox="0 0 24 24"
					>
						<path
							strokeLinecap="round"
							strokeLinejoin="round"
							strokeWidth={2}
							d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.667-2.308-1.667-3.08 0L3.34 19c-.77 1.333.192 3 1.732 3z"
						/>
					</svg>
				);
			case 'error':
				return (
					<svg
						className="w-5 h-5 text-red-400"
						fill="none"
						stroke="currentColor"
						viewBox="0 0 24 24"
					>
						<path
							strokeLinecap="round"
							strokeLinejoin="round"
							strokeWidth={2}
							d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
						/>
					</svg>
				);
		}
	};

	const bgColor = {
		success: 'bg-green-900/90',
		info: 'bg-blue-900/90',
		warning: 'bg-yellow-900/90',
		error: 'bg-red-900/90'
	}[notification.type];

	const borderColor = {
		success: 'border-green-600',
		info: 'border-blue-600',
		warning: 'border-yellow-600',
		error: 'border-red-600'
	}[notification.type];

	const progressColor = {
		success: 'bg-green-400',
		info: 'bg-blue-400',
		warning: 'bg-yellow-400',
		error: 'bg-red-400'
	}[notification.type];

	return (
		<div
			className={`${bgColor} ${borderColor} border rounded-lg shadow-lg p-4 mb-2 transition-all duration-300 ${
				isVisible ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-full'
			} max-w-sm w-full relative overflow-hidden`}
		>
			<div className="flex items-start">
				<div className="flex-shrink-0">{getIcon()}</div>
				<div className="ml-3 flex-1">
					<h3 className="text-sm font-medium text-white">
						{notification.title}
					</h3>
					<p className="mt-1 text-sm text-gray-300">{notification.message}</p>
				</div>
				<button
					onClick={() => onDismiss(notification.id)}
					className="ml-4 flex-shrink-0 inline-flex text-gray-400 hover:text-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white"
				>
					<span className="sr-only">Close</span>
					<svg className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
						<path
							fillRule="evenodd"
							d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
							clipRule="evenodd"
						/>
					</svg>
				</button>
			</div>
			{/* Progress bar */}
			<div className="absolute bottom-0 left-0 w-full h-1 bg-gray-700">
				<div
					className={`h-full ${progressColor} transition-all duration-100 ease-linear`}
					style={{ width: `${progress}%` }}
				/>
			</div>
		</div>
	);
};

```

--------------------------------------------------------------------------------
/apps/extension/esbuild.js:
--------------------------------------------------------------------------------

```javascript
const esbuild = require('esbuild');
const path = require('path');

const production = process.argv.includes('--production');
const watch = process.argv.includes('--watch');

/**
 * @type {import('esbuild').Plugin}
 */
const esbuildProblemMatcherPlugin = {
	name: 'esbuild-problem-matcher',

	setup(build) {
		build.onStart(() => {
			console.log('[watch] build started');
		});
		build.onEnd((result) => {
			result.errors.forEach(({ text, location }) => {
				console.error(`✘ [ERROR] ${text}`);
				console.error(
					`    ${location.file}:${location.line}:${location.column}:`
				);
			});
			console.log('[watch] build finished');
		});
	}
};

/**
 * @type {import('esbuild').Plugin}
 */
const aliasPlugin = {
	name: 'alias',
	setup(build) {
		// Handle @/ aliases for shadcn/ui
		build.onResolve({ filter: /^@\// }, (args) => {
			const resolvedPath = path.resolve(__dirname, 'src', args.path.slice(2));

			// Try to resolve with common TypeScript extensions
			const fs = require('fs');
			const extensions = ['.tsx', '.ts', '.jsx', '.js'];

			// Check if it's a file first
			for (const ext of extensions) {
				const fullPath = resolvedPath + ext;
				if (fs.existsSync(fullPath)) {
					return { path: fullPath };
				}
			}

			// Check if it's a directory with index file
			for (const ext of extensions) {
				const indexPath = path.join(resolvedPath, 'index' + ext);
				if (fs.existsSync(indexPath)) {
					return { path: indexPath };
				}
			}

			// Fallback to original behavior
			return { path: resolvedPath };
		});
	}
};

async function main() {
	// Build configuration for the VS Code extension
	const extensionCtx = await esbuild.context({
		entryPoints: ['src/extension.ts'],
		bundle: true,
		format: 'cjs',
		minify: production,
		sourcemap: !production ? 'inline' : false,
		sourcesContent: !production,
		platform: 'node',
		outdir: 'dist',
		external: ['vscode'],
		logLevel: 'silent',
		// Add production optimizations
		...(production && {
			drop: ['debugger'],
			pure: ['console.log', 'console.debug', 'console.trace']
		}),
		plugins: [esbuildProblemMatcherPlugin, aliasPlugin]
	});

	// Build configuration for the React webview
	const webviewCtx = await esbuild.context({
		entryPoints: ['src/webview/index.tsx'],
		bundle: true,
		format: 'iife',
		globalName: 'App',
		minify: production,
		sourcemap: !production ? 'inline' : false,
		sourcesContent: !production,
		platform: 'browser',
		outdir: 'dist',
		logLevel: 'silent',
		target: ['es2020'],
		jsx: 'automatic',
		jsxImportSource: 'react',
		external: ['*.css'],
		// Bundle React with webview since it's not available in the runtime
		// This prevents the multiple React instances issue
		// Ensure React is resolved from the workspace root to avoid duplicates
		alias: {
			react: path.resolve(__dirname, '../../node_modules/react'),
			'react-dom': path.resolve(__dirname, '../../node_modules/react-dom')
		},
		define: {
			'process.env.NODE_ENV': production ? '"production"' : '"development"',
			global: 'globalThis'
		},
		// Add production optimizations for webview too
		...(production && {
			drop: ['debugger'],
			pure: ['console.log', 'console.debug', 'console.trace']
		}),
		plugins: [esbuildProblemMatcherPlugin, aliasPlugin]
	});

	// Build configuration for the React sidebar
	const sidebarCtx = await esbuild.context({
		entryPoints: ['src/webview/sidebar.tsx'],
		bundle: true,
		format: 'iife',
		globalName: 'SidebarApp',
		minify: production,
		sourcemap: !production ? 'inline' : false,
		sourcesContent: !production,
		platform: 'browser',
		outdir: 'dist',
		logLevel: 'silent',
		target: ['es2020'],
		jsx: 'automatic',
		jsxImportSource: 'react',
		external: ['*.css'],
		alias: {
			react: path.resolve(__dirname, '../../node_modules/react'),
			'react-dom': path.resolve(__dirname, '../../node_modules/react-dom')
		},
		define: {
			'process.env.NODE_ENV': production ? '"production"' : '"development"',
			global: 'globalThis'
		},
		...(production && {
			drop: ['debugger'],
			pure: ['console.log', 'console.debug', 'console.trace']
		}),
		plugins: [esbuildProblemMatcherPlugin, aliasPlugin]
	});

	if (watch) {
		await Promise.all([
			extensionCtx.watch(),
			webviewCtx.watch(),
			sidebarCtx.watch()
		]);
	} else {
		await Promise.all([
			extensionCtx.rebuild(),
			webviewCtx.rebuild(),
			sidebarCtx.rebuild()
		]);
		await extensionCtx.dispose();
		await webviewCtx.dispose();
		await sidebarCtx.dispose();
	}
}

main().catch((e) => {
	console.error(e);
	process.exit(1);
});

```

--------------------------------------------------------------------------------
/tests/unit/scripts/modules/task-manager/setup.js:
--------------------------------------------------------------------------------

```javascript
/**
 * Common setup for task-manager module tests
 */
import { jest } from '@jest/globals';

// Sample test data
export const sampleTasks = {
	meta: { projectName: 'Test Project' },
	tasks: [
		{
			id: 1,
			title: 'Task 1',
			description: 'First task description',
			status: 'pending',
			dependencies: [],
			priority: 'high',
			details: 'Detailed information for task 1',
			testStrategy: 'Test strategy for task 1'
		},
		{
			id: 2,
			title: 'Task 2',
			description: 'Second task description',
			status: 'pending',
			dependencies: [1],
			priority: 'medium',
			details: 'Detailed information for task 2',
			testStrategy: 'Test strategy for task 2'
		},
		{
			id: 3,
			title: 'Task with Subtasks',
			description: 'Task with subtasks description',
			status: 'pending',
			dependencies: [1, 2],
			priority: 'high',
			details: 'Detailed information for task 3',
			testStrategy: 'Test strategy for task 3',
			subtasks: [
				{
					id: 1,
					title: 'Subtask 1',
					description: 'First subtask',
					status: 'pending',
					dependencies: [],
					details: 'Details for subtask 1'
				},
				{
					id: 2,
					title: 'Subtask 2',
					description: 'Second subtask',
					status: 'pending',
					dependencies: [1],
					details: 'Details for subtask 2'
				}
			]
		}
	]
};

export const emptySampleTasks = {
	meta: { projectName: 'Empty Project' },
	tasks: []
};

export const sampleClaudeResponse = {
	tasks: [
		{
			id: 1,
			title: 'Setup Project',
			description: 'Initialize the project structure',
			status: 'pending',
			dependencies: [],
			priority: 'high',
			details:
				'Create repository, configure build system, and setup dev environment',
			testStrategy: 'Verify project builds and tests run'
		},
		{
			id: 2,
			title: 'Implement Core Feature',
			description: 'Create the main functionality',
			status: 'pending',
			dependencies: [1],
			priority: 'high',
			details: 'Implement the core business logic for the application',
			testStrategy:
				'Unit tests for core functions, integration tests for workflows'
		}
	]
};

// Common mock setup function
export const setupCommonMocks = () => {
	// Clear mocks before setup
	jest.clearAllMocks();

	// Mock implementations
	const mocks = {
		readFileSync: jest.fn(),
		existsSync: jest.fn(),
		mkdirSync: jest.fn(),
		writeFileSync: jest.fn(),
		readJSON: jest.fn(),
		writeJSON: jest.fn(),
		log: jest.fn(),
		isTaskDependentOn: jest.fn().mockReturnValue(false),
		formatDependenciesWithStatus: jest.fn(),
		displayTaskList: jest.fn(),
		validateAndFixDependencies: jest.fn(),
		generateObjectService: jest.fn().mockResolvedValue({
			mainResult: { tasks: [] },
			telemetryData: {}
		})
	};

	return mocks;
};

// Helper to create a deep copy of objects to avoid test pollution
export const cloneData = (data) => JSON.parse(JSON.stringify(data));

/**
 * Shared mock implementation for getTagAwareFilePath that matches the actual implementation
 * This ensures consistent behavior across all test files, particularly regarding projectRoot handling.
 *
 * The key difference from previous inconsistent implementations was that some tests were not
 * properly handling the projectRoot parameter, leading to different behaviors between test files.
 *
 * @param {string} basePath - The base file path
 * @param {string|null} tag - The tag name (null, undefined, or 'master' uses base path)
 * @param {string} [projectRoot='.'] - The project root directory
 * @returns {string} The resolved file path
 */
export const createGetTagAwareFilePathMock = () => {
	return jest.fn((basePath, tag, projectRoot = '.') => {
		// Handle projectRoot consistently - this was the key fix
		const fullPath = projectRoot ? `${projectRoot}/${basePath}` : basePath;

		if (!tag || tag === 'master') {
			return fullPath;
		}

		// Mock the slugification behavior (matches actual implementation)
		const slugifiedTag = tag.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();
		const idx = fullPath.lastIndexOf('.');
		return `${fullPath.slice(0, idx)}_${slugifiedTag}${fullPath.slice(idx)}`;
	});
};

/**
 * Shared mock implementation for slugifyTagForFilePath that matches the actual implementation
 * @param {string} tagName - The tag name to slugify
 * @returns {string} Slugified tag name safe for filesystem use
 */
export const createSlugifyTagForFilePathMock = () => {
	return jest.fn((tagName) => {
		if (!tagName || typeof tagName !== 'string') {
			return 'unknown-tag';
		}
		return tagName.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();
	});
};

```

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

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

// Mock external modules
jest.mock('child_process', () => ({
	execSync: jest.fn()
}));

// Mock console methods
jest.mock('console', () => ({
	log: jest.fn(),
	info: jest.fn(),
	warn: jest.fn(),
	error: jest.fn(),
	clear: jest.fn()
}));

describe('Gemini Profile Integration', () => {
	let tempDir;

	beforeEach(() => {
		jest.clearAllMocks();

		// Create a temporary directory for testing
		tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'task-master-test-'));

		// Spy on fs methods
		jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
		jest.spyOn(fs, 'readFileSync').mockImplementation((filePath) => {
			if (filePath.toString().includes('AGENTS.md')) {
				return 'Sample AGENTS.md content for Gemini integration';
			}
			return '{}';
		});
		jest.spyOn(fs, 'existsSync').mockImplementation(() => false);
		jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {});
	});

	afterEach(() => {
		// Clean up the temporary directory
		try {
			fs.rmSync(tempDir, { recursive: true, force: true });
		} catch (err) {
			console.error(`Error cleaning up: ${err.message}`);
		}
	});

	// Test function that simulates the Gemini profile file copying behavior
	function mockCreateGeminiStructure() {
		// Gemini profile copies AGENTS.md to GEMINI.md in project root
		const sourceContent = 'Sample AGENTS.md content for Gemini integration';
		fs.writeFileSync(path.join(tempDir, 'GEMINI.md'), sourceContent);

		// Gemini profile creates .gemini directory
		fs.mkdirSync(path.join(tempDir, '.gemini'), { recursive: true });

		// Gemini profile creates settings.json in .gemini directory
		const settingsContent = JSON.stringify(
			{
				mcpServers: {
					'task-master-ai': {
						command: 'npx',
						args: ['-y', 'task-master-ai'],
						env: {
							YOUR_ANTHROPIC_API_KEY: 'your-api-key-here',
							YOUR_PERPLEXITY_API_KEY: 'your-api-key-here',
							YOUR_OPENAI_API_KEY: 'your-api-key-here',
							YOUR_GOOGLE_API_KEY: 'your-api-key-here',
							YOUR_MISTRAL_API_KEY: 'your-api-key-here',
							YOUR_AZURE_OPENAI_API_KEY: 'your-api-key-here',
							YOUR_AZURE_OPENAI_ENDPOINT: 'your-endpoint-here',
							YOUR_OPENROUTER_API_KEY: 'your-api-key-here',
							YOUR_XAI_API_KEY: 'your-api-key-here',
							YOUR_OLLAMA_API_KEY: 'your-api-key-here',
							YOUR_OLLAMA_BASE_URL: 'http://localhost:11434/api',
							YOUR_AWS_ACCESS_KEY_ID: 'your-access-key-id',
							YOUR_AWS_SECRET_ACCESS_KEY: 'your-secret-access-key',
							YOUR_AWS_REGION: 'us-east-1'
						}
					}
				}
			},
			null,
			2
		);
		fs.writeFileSync(
			path.join(tempDir, '.gemini', 'settings.json'),
			settingsContent
		);
	}

	test('creates GEMINI.md file in project root', () => {
		// Act
		mockCreateGeminiStructure();

		// Assert
		expect(fs.writeFileSync).toHaveBeenCalledWith(
			path.join(tempDir, 'GEMINI.md'),
			'Sample AGENTS.md content for Gemini integration'
		);
	});

	test('creates .gemini profile directory', () => {
		// Act
		mockCreateGeminiStructure();

		// Assert
		expect(fs.mkdirSync).toHaveBeenCalledWith(path.join(tempDir, '.gemini'), {
			recursive: true
		});
	});

	test('creates MCP configuration as settings.json', () => {
		// Act
		mockCreateGeminiStructure();

		// Assert - Gemini profile should create settings.json instead of mcp.json
		const writeFileCalls = fs.writeFileSync.mock.calls;
		const settingsJsonCall = writeFileCalls.find((call) =>
			call[0].toString().includes('.gemini/settings.json')
		);
		expect(settingsJsonCall).toBeDefined();
	});

	test('uses settings.json instead of mcp.json', () => {
		// Act
		mockCreateGeminiStructure();

		// Assert - Should use settings.json, not mcp.json
		const writeFileCalls = fs.writeFileSync.mock.calls;
		const mcpJsonCalls = writeFileCalls.filter((call) =>
			call[0].toString().includes('mcp.json')
		);
		expect(mcpJsonCalls).toHaveLength(0);

		const settingsJsonCalls = writeFileCalls.filter((call) =>
			call[0].toString().includes('settings.json')
		);
		expect(settingsJsonCalls).toHaveLength(1);
	});

	test('renames AGENTS.md to GEMINI.md', () => {
		// Act
		mockCreateGeminiStructure();

		// Assert - Gemini should rename AGENTS.md to GEMINI.md
		const writeFileCalls = fs.writeFileSync.mock.calls;
		const geminiMdCall = writeFileCalls.find((call) =>
			call[0].toString().includes('GEMINI.md')
		);
		expect(geminiMdCall).toBeDefined();
		expect(geminiMdCall[0]).toBe(path.join(tempDir, 'GEMINI.md'));
	});
});

```

--------------------------------------------------------------------------------
/src/ai-providers/google-vertex.js:
--------------------------------------------------------------------------------

```javascript
/**
 * google-vertex.js
 * AI provider implementation for Google Vertex AI models using Vercel AI SDK.
 */

import { createVertex } from '@ai-sdk/google-vertex';
import { BaseAIProvider } from './base-provider.js';
import { resolveEnvVariable } from '../../scripts/modules/utils.js';
import { log } from '../../scripts/modules/utils.js';

// Vertex-specific error classes
class VertexAuthError extends Error {
	constructor(message) {
		super(message);
		this.name = 'VertexAuthError';
		this.code = 'vertex_auth_error';
	}
}

class VertexConfigError extends Error {
	constructor(message) {
		super(message);
		this.name = 'VertexConfigError';
		this.code = 'vertex_config_error';
	}
}

class VertexApiError extends Error {
	constructor(message, statusCode) {
		super(message);
		this.name = 'VertexApiError';
		this.code = 'vertex_api_error';
		this.statusCode = statusCode;
	}
}

export class VertexAIProvider extends BaseAIProvider {
	constructor() {
		super();
		this.name = 'Google Vertex AI';
	}

	/**
	 * Returns the required API key environment variable name for Google Vertex AI.
	 * @returns {string} The environment variable name
	 */
	getRequiredApiKeyName() {
		return 'GOOGLE_API_KEY';
	}

	/**
	 * Validates Vertex AI-specific authentication parameters
	 * @param {object} params - Parameters to validate
	 * @throws {Error} If required parameters are missing
	 */
	validateAuth(params) {
		const { apiKey, projectId, location, credentials } = params;

		// Check for API key OR service account credentials
		if (!apiKey && !credentials) {
			throw new VertexAuthError(
				'Either Google API key (GOOGLE_API_KEY) or service account credentials (GOOGLE_APPLICATION_CREDENTIALS) is required for Vertex AI'
			);
		}

		// Project ID is required for Vertex AI
		if (!projectId) {
			throw new VertexConfigError(
				'Google Cloud project ID is required for Vertex AI. Set VERTEX_PROJECT_ID environment variable.'
			);
		}

		// Location is required for Vertex AI
		if (!location) {
			throw new VertexConfigError(
				'Google Cloud location is required for Vertex AI. Set VERTEX_LOCATION environment variable (e.g., "us-central1").'
			);
		}
	}

	/**
	 * Creates and returns a Google Vertex AI client instance.
	 * @param {object} params - Parameters for client initialization
	 * @param {string} [params.apiKey] - Google API key
	 * @param {string} params.projectId - Google Cloud project ID
	 * @param {string} params.location - Google Cloud location (e.g., "us-central1")
	 * @param {object} [params.credentials] - Service account credentials object
	 * @param {string} [params.baseURL] - Optional custom API endpoint
	 * @returns {Function} Google Vertex AI client function
	 * @throws {Error} If required parameters are missing or initialization fails
	 */
	getClient(params) {
		try {
			// Validate required parameters
			this.validateAuth(params);

			const { apiKey, projectId, location, credentials, baseURL } = params;

			// Configure auth options - either API key or service account
			const authOptions = {};
			if (apiKey) {
				authOptions.apiKey = apiKey;
			} else if (credentials) {
				authOptions.googleAuthOptions = credentials;
			}

			// Return Vertex AI client
			return createVertex({
				...authOptions,
				projectId,
				location,
				...(baseURL && { baseURL })
			});
		} catch (error) {
			this.handleError('client initialization', error);
		}
	}

	/**
	 * Handle errors from Vertex AI
	 * @param {string} operation - Description of the operation that failed
	 * @param {Error} error - The error object
	 * @throws {Error} Rethrows the error with additional context
	 */
	handleError(operation, error) {
		log('error', `Vertex AI ${operation} error:`, error);

		// Handle known error types
		if (
			error.name === 'VertexAuthError' ||
			error.name === 'VertexConfigError' ||
			error.name === 'VertexApiError'
		) {
			throw error;
		}

		// Handle network/API errors
		if (error.response) {
			const statusCode = error.response.status;
			const errorMessage = error.response.data?.error?.message || error.message;

			// Categorize by status code
			if (statusCode === 401 || statusCode === 403) {
				throw new VertexAuthError(`Authentication failed: ${errorMessage}`);
			} else if (statusCode === 400) {
				throw new VertexConfigError(`Invalid request: ${errorMessage}`);
			} else {
				throw new VertexApiError(
					`API error (${statusCode}): ${errorMessage}`,
					statusCode
				);
			}
		}

		// Generic error handling
		throw new Error(`Vertex AI ${operation} failed: ${error.message}`);
	}
}

```

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

```typescript
/**
 * @fileoverview Configuration Persistence Service
 * Handles saving and backup of configuration files
 */

import { promises as fs } from 'node:fs';
import path from 'node:path';
import type { PartialConfiguration } from '../../interfaces/configuration.interface.js';
import {
	ERROR_CODES,
	TaskMasterError
} from '../../errors/task-master-error.js';

/**
 * Persistence options
 */
export interface PersistenceOptions {
	/** Enable backup before saving */
	createBackup?: boolean;
	/** Maximum number of backups to keep */
	maxBackups?: number;
	/** Use atomic write operations */
	atomic?: boolean;
}

/**
 * ConfigPersistence handles all configuration file I/O operations
 * Single responsibility: Configuration persistence
 */
export class ConfigPersistence {
	private localConfigPath: string;
	private backupDir: string;

	constructor(projectRoot: string) {
		this.localConfigPath = path.join(projectRoot, '.taskmaster', 'config.json');
		this.backupDir = path.join(projectRoot, '.taskmaster', 'backups');
	}

	/**
	 * Save configuration to file
	 */
	async saveConfig(
		config: PartialConfiguration,
		options: PersistenceOptions = {}
	): Promise<void> {
		const { createBackup = false, atomic = true } = options;

		try {
			// Create backup if requested
			if (createBackup && (await this.configExists())) {
				await this.createBackup();
			}

			// Ensure directory exists
			const configDir = path.dirname(this.localConfigPath);
			await fs.mkdir(configDir, { recursive: true });

			const jsonContent = JSON.stringify(config, null, 2);

			if (atomic) {
				// Atomic write: write to temp file then rename
				const tempPath = `${this.localConfigPath}.tmp`;
				await fs.writeFile(tempPath, jsonContent, 'utf-8');
				await fs.rename(tempPath, this.localConfigPath);
			} else {
				// Direct write
				await fs.writeFile(this.localConfigPath, jsonContent, 'utf-8');
			}
		} catch (error) {
			throw new TaskMasterError(
				'Failed to save configuration',
				ERROR_CODES.CONFIG_ERROR,
				{ configPath: this.localConfigPath },
				error as Error
			);
		}
	}

	/**
	 * Create a backup of the current configuration
	 */
	private async createBackup(): Promise<string> {
		try {
			await fs.mkdir(this.backupDir, { recursive: true });

			const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
			const backupPath = path.join(this.backupDir, `config-${timestamp}.json`);

			const configContent = await fs.readFile(this.localConfigPath, 'utf-8');
			await fs.writeFile(backupPath, configContent, 'utf-8');

			// Clean old backups
			await this.cleanOldBackups();

			return backupPath;
		} catch (error) {
			console.warn('Failed to create backup:', error);
			throw error;
		}
	}

	/**
	 * Clean old backup files
	 */
	private async cleanOldBackups(maxBackups = 5): Promise<void> {
		try {
			const files = await fs.readdir(this.backupDir);
			const backupFiles = files
				.filter((f) => f.startsWith('config-') && f.endsWith('.json'))
				.sort()
				.reverse();

			// Remove old backups
			const toDelete = backupFiles.slice(maxBackups);
			for (const file of toDelete) {
				await fs.unlink(path.join(this.backupDir, file));
			}
		} catch (error) {
			console.warn('Failed to clean old backups:', error);
		}
	}

	/**
	 * Check if config file exists
	 */
	async configExists(): Promise<boolean> {
		try {
			await fs.access(this.localConfigPath);
			return true;
		} catch {
			return false;
		}
	}

	/**
	 * Delete configuration file
	 */
	async deleteConfig(): Promise<void> {
		try {
			await fs.unlink(this.localConfigPath);
		} catch (error: any) {
			if (error.code !== 'ENOENT') {
				throw new TaskMasterError(
					'Failed to delete configuration',
					ERROR_CODES.CONFIG_ERROR,
					{ configPath: this.localConfigPath },
					error
				);
			}
		}
	}

	/**
	 * Get list of available backups
	 */
	async getBackups(): Promise<string[]> {
		try {
			const files = await fs.readdir(this.backupDir);
			return files
				.filter((f) => f.startsWith('config-') && f.endsWith('.json'))
				.sort()
				.reverse();
		} catch {
			return [];
		}
	}

	/**
	 * Restore from a backup
	 */
	async restoreFromBackup(backupFile: string): Promise<void> {
		const backupPath = path.join(this.backupDir, backupFile);

		try {
			const backupContent = await fs.readFile(backupPath, 'utf-8');
			await fs.writeFile(this.localConfigPath, backupContent, 'utf-8');
		} catch (error) {
			throw new TaskMasterError(
				'Failed to restore from backup',
				ERROR_CODES.CONFIG_ERROR,
				{ backupPath },
				error as Error
			);
		}
	}
}

```

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

```javascript
/**
 * Tests for the updateSingleTaskStatus function
 */
import { jest } from '@jest/globals';

// Import test fixtures
import {
	isValidTaskStatus,
	TASK_STATUS_OPTIONS
} from '../../../../../src/constants/task-status.js';

// Sample tasks data for testing
const sampleTasks = {
	tasks: [
		{
			id: 1,
			title: 'Task 1',
			description: 'First task',
			status: 'pending',
			dependencies: []
		},
		{
			id: 2,
			title: 'Task 2',
			description: 'Second task',
			status: 'pending',
			dependencies: []
		},
		{
			id: 3,
			title: 'Task 3',
			description: 'Third task with subtasks',
			status: 'pending',
			dependencies: [],
			subtasks: [
				{
					id: 1,
					title: 'Subtask 3.1',
					description: 'First subtask',
					status: 'pending',
					dependencies: []
				},
				{
					id: 2,
					title: 'Subtask 3.2',
					description: 'Second subtask',
					status: 'pending',
					dependencies: []
				}
			]
		}
	]
};

// Simplified version of updateSingleTaskStatus for testing
const testUpdateSingleTaskStatus = (tasksData, taskIdInput, newStatus) => {
	if (!isValidTaskStatus(newStatus)) {
		throw new Error(
			`Error: Invalid status value: ${newStatus}. Use one of: ${TASK_STATUS_OPTIONS.join(', ')}`
		);
	}

	// Check if it's a subtask (e.g., "1.2")
	if (taskIdInput.includes('.')) {
		const [parentId, subtaskId] = taskIdInput
			.split('.')
			.map((id) => parseInt(id, 10));

		// Find the parent task
		const parentTask = tasksData.tasks.find((t) => t.id === parentId);
		if (!parentTask) {
			throw new Error(`Parent task ${parentId} not found`);
		}

		// Find the subtask
		if (!parentTask.subtasks) {
			throw new Error(`Parent task ${parentId} has no subtasks`);
		}

		const subtask = parentTask.subtasks.find((st) => st.id === subtaskId);
		if (!subtask) {
			throw new Error(
				`Subtask ${subtaskId} not found in parent task ${parentId}`
			);
		}

		// Update the subtask status
		subtask.status = newStatus;

		// Check if all subtasks are done (if setting to 'done')
		if (
			newStatus.toLowerCase() === 'done' ||
			newStatus.toLowerCase() === 'completed'
		) {
			const allSubtasksDone = parentTask.subtasks.every(
				(st) => st.status === 'done' || st.status === 'completed'
			);

			// For testing, we don't need to output suggestions
		}
	} else {
		// Handle regular task
		const taskId = parseInt(taskIdInput, 10);
		const task = tasksData.tasks.find((t) => t.id === taskId);

		if (!task) {
			throw new Error(`Task ${taskId} not found`);
		}

		// Update the task status
		task.status = newStatus;

		// If marking as done, also mark all subtasks as done
		if (
			(newStatus.toLowerCase() === 'done' ||
				newStatus.toLowerCase() === 'completed') &&
			task.subtasks &&
			task.subtasks.length > 0
		) {
			task.subtasks.forEach((subtask) => {
				subtask.status = newStatus;
			});
		}
	}

	return true;
};

describe('updateSingleTaskStatus function', () => {
	test('should update regular task status', async () => {
		// Arrange
		const testTasksData = JSON.parse(JSON.stringify(sampleTasks));

		// Act
		const result = testUpdateSingleTaskStatus(testTasksData, '2', 'done');

		// Assert
		expect(result).toBe(true);
		expect(testTasksData.tasks[1].status).toBe('done');
	});

	test('should throw error for invalid status', async () => {
		// Arrange
		const testTasksData = JSON.parse(JSON.stringify(sampleTasks));

		// Assert
		expect(() =>
			testUpdateSingleTaskStatus(testTasksData, '2', 'Done')
		).toThrow(/Error: Invalid status value: Done./);
	});

	test('should update subtask status', async () => {
		// Arrange
		const testTasksData = JSON.parse(JSON.stringify(sampleTasks));

		// Act
		const result = testUpdateSingleTaskStatus(testTasksData, '3.1', 'done');

		// Assert
		expect(result).toBe(true);
		expect(testTasksData.tasks[2].subtasks[0].status).toBe('done');
	});

	test('should handle parent tasks without subtasks', async () => {
		// Arrange
		const testTasksData = JSON.parse(JSON.stringify(sampleTasks));

		// Remove subtasks from task 3
		const taskWithoutSubtasks = { ...testTasksData.tasks[2] };
		delete taskWithoutSubtasks.subtasks;
		testTasksData.tasks[2] = taskWithoutSubtasks;

		// Assert
		expect(() =>
			testUpdateSingleTaskStatus(testTasksData, '3.1', 'done')
		).toThrow('has no subtasks');
	});

	test('should handle non-existent subtask ID', async () => {
		// Arrange
		const testTasksData = JSON.parse(JSON.stringify(sampleTasks));

		// Assert
		expect(() =>
			testUpdateSingleTaskStatus(testTasksData, '3.99', 'done')
		).toThrow('Subtask 99 not found');
	});
});

```
Page 8/38FirstPrevNextLast